mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-10-24 12:17:39 +00:00
Fix server options (#5899)
* removed illegal cahracter in filename
* fixes required plugin options & updates docs
* Update dev docs
* call self.displayError
* Revert "call self.displayError"
This reverts commit 5d599aa979.
* adds path based auth (backwards compatible)
* refactor per-route auth
* get status bug
* server options
* server options
* server options, new 'server-settings' param
* reflow
* fix boot.origin
* refactor new parameters
* restore sitetitle as servername option
* Soft reset to master
* docs update
* tweak wording
* docs
* cleanup
* remove literal string
* cleanup docs
* formatting
* Remove per-path auth
* revert get-status
* fold in PR 5538
* remove server-options
* remove doc
* required-plugins a server-parameter, not option
This commit is contained in:
@@ -34,7 +34,6 @@ function Server(options) {
|
|||||||
this.authenticators = options.authenticators || [];
|
this.authenticators = options.authenticators || [];
|
||||||
this.wiki = options.wiki;
|
this.wiki = options.wiki;
|
||||||
this.boot = options.boot || $tw.boot;
|
this.boot = options.boot || $tw.boot;
|
||||||
this.servername = $tw.utils.transliterateToSafeASCII(this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
|
||||||
// Initialise the variables
|
// Initialise the variables
|
||||||
this.variables = $tw.utils.extend({},this.defaultVariables);
|
this.variables = $tw.utils.extend({},this.defaultVariables);
|
||||||
if(options.variables) {
|
if(options.variables) {
|
||||||
@@ -44,7 +43,8 @@ function Server(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$tw.utils.extend({},this.defaultVariables,options.variables);
|
// Setup the default required plugins
|
||||||
|
this.requiredPlugins = this.get("required-plugins").split(',');
|
||||||
// Initialise CSRF
|
// Initialise CSRF
|
||||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||||
// Initialize Gzip compression
|
// Initialize Gzip compression
|
||||||
@@ -52,14 +52,24 @@ function Server(options) {
|
|||||||
// Initialize browser-caching
|
// Initialize browser-caching
|
||||||
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
||||||
// Initialise authorization
|
// Initialise authorization
|
||||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
var authorizedUserName;
|
||||||
|
if(this.get("username") && this.get("password")) {
|
||||||
|
authorizedUserName = this.get("username");
|
||||||
|
} else if(this.get("credentials")) {
|
||||||
|
authorizedUserName = "(authenticated)";
|
||||||
|
} else {
|
||||||
|
authorizedUserName = "(anon)";
|
||||||
|
}
|
||||||
this.authorizationPrincipals = {
|
this.authorizationPrincipals = {
|
||||||
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
||||||
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
||||||
}
|
}
|
||||||
|
if(this.get("admin") || authorizedUserName !== "(anon)") {
|
||||||
|
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
|
||||||
|
}
|
||||||
// Load and initialise authenticators
|
// Load and initialise authenticators
|
||||||
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
||||||
// console.log("Loading server route " + title);
|
// console.log("Loading authenticator " + title);
|
||||||
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
|
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
|
||||||
});
|
});
|
||||||
// Load route handlers
|
// Load route handlers
|
||||||
@@ -71,15 +81,21 @@ function Server(options) {
|
|||||||
this.listenOptions = null;
|
this.listenOptions = null;
|
||||||
this.protocol = "http";
|
this.protocol = "http";
|
||||||
var tlsKeyFilepath = this.get("tls-key"),
|
var tlsKeyFilepath = this.get("tls-key"),
|
||||||
tlsCertFilepath = this.get("tls-cert");
|
tlsCertFilepath = this.get("tls-cert"),
|
||||||
|
tlsPassphrase = this.get("tls-passphrase");
|
||||||
if(tlsCertFilepath && tlsKeyFilepath) {
|
if(tlsCertFilepath && tlsKeyFilepath) {
|
||||||
this.listenOptions = {
|
this.listenOptions = {
|
||||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8")
|
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
|
||||||
|
passphrase: tlsPassphrase || ''
|
||||||
};
|
};
|
||||||
this.protocol = "https";
|
this.protocol = "https";
|
||||||
}
|
}
|
||||||
this.transport = require(this.protocol);
|
this.transport = require(this.protocol);
|
||||||
|
// Name the server and init the boot state
|
||||||
|
this.servername = $tw.utils.transliterateToSafeASCII(this.get("server-name") || this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
||||||
|
this.boot.origin = this.get("origin")? this.get("origin"): this.protocol+"://"+this.get("host")+":"+this.get("port");
|
||||||
|
this.boot.pathPrefix = this.get("path-prefix") || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -150,6 +166,7 @@ function sendResponse(request,response,statusCode,headers,data,encoding) {
|
|||||||
Server.prototype.defaultVariables = {
|
Server.prototype.defaultVariables = {
|
||||||
port: "8080",
|
port: "8080",
|
||||||
host: "127.0.0.1",
|
host: "127.0.0.1",
|
||||||
|
"required-plugins": "$:/plugins/tiddlywiki/filesystem,$:/plugins/tiddlywiki/tiddlyweb",
|
||||||
"root-tiddler": "$:/core/save/all",
|
"root-tiddler": "$:/core/save/all",
|
||||||
"root-render-type": "text/plain",
|
"root-render-type": "text/plain",
|
||||||
"root-serve-type": "text/html",
|
"root-serve-type": "text/html",
|
||||||
@@ -239,15 +256,15 @@ Server.prototype.requestHandler = function(request,response,options) {
|
|||||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||||
state.sendResponse = sendResponse.bind(self,request,response);
|
state.sendResponse = sendResponse.bind(self,request,response);
|
||||||
// Get the principals authorized to access this resource
|
// Get the principals authorized to access this resource
|
||||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
||||||
// Check for the CSRF header if this is a write
|
// Check for the CSRF header if this is a write
|
||||||
if(!this.csrfDisable && authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
if(!this.csrfDisable && state.authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
||||||
response.writeHead(403,"'X-Requested-With' header required to login to '" + this.servername + "'");
|
response.writeHead(403,"'X-Requested-With' header required to login to '" + this.servername + "'");
|
||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check whether anonymous access is granted
|
// Check whether anonymous access is granted
|
||||||
state.allowAnon = this.isAuthorized(authorizationType,null);
|
state.allowAnon = this.isAuthorized(state.authorizationType,null);
|
||||||
// Authenticate with the first active authenticator
|
// Authenticate with the first active authenticator
|
||||||
if(this.authenticators.length > 0) {
|
if(this.authenticators.length > 0) {
|
||||||
if(!this.authenticators[0].authenticateRequest(request,response,state)) {
|
if(!this.authenticators[0].authenticateRequest(request,response,state)) {
|
||||||
@@ -256,7 +273,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Authorize with the authenticated username
|
// Authorize with the authenticated username
|
||||||
if(!this.isAuthorized(authorizationType,state.authenticatedUsername)) {
|
if(!this.isAuthorized(state.authorizationType,state.authenticatedUsername)) {
|
||||||
response.writeHead(401,"'" + state.authenticatedUsername + "' is not authorized to access '" + this.servername + "'");
|
response.writeHead(401,"'" + state.authenticatedUsername + "' is not authorized to access '" + this.servername + "'");
|
||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
@@ -322,8 +339,16 @@ Server.prototype.listen = function(port,host,prefix) {
|
|||||||
port = process.env[port] || 8080;
|
port = process.env[port] || 8080;
|
||||||
}
|
}
|
||||||
// Warn if required plugins are missing
|
// Warn if required plugins are missing
|
||||||
if(!this.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !this.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {
|
var missing = [];
|
||||||
$tw.utils.warning("Warning: Plugins required for client-server operation (\"tiddlywiki/filesystem\" and \"tiddlywiki/tiddlyweb\") are missing from tiddlywiki.info file");
|
for (var index=0; index<this.requiredPlugins.length; index++) {
|
||||||
|
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
|
||||||
|
missing.push(this.requiredPlugins[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(missing.length > 0) {
|
||||||
|
var error = "Warning: Plugin(s) required for client-server operation are missing.\n"+
|
||||||
|
"\""+ missing.join("\", \"")+"\"";
|
||||||
|
$tw.utils.warning(error);
|
||||||
}
|
}
|
||||||
// Create the server
|
// Create the server
|
||||||
var server;
|
var server;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
chapter.of: Extended Persistence
|
chapter.of: Extended Persistence
|
||||||
created: 20140708084850294
|
created: 20140708084850294
|
||||||
modified: 20140717181245449
|
modified: 20210720193245000
|
||||||
sub.num: 3
|
sub.num: 3
|
||||||
tags: doc
|
tags: doc
|
||||||
title: Syncadaptor
|
title: Syncadaptor
|
||||||
|
|
||||||
A module with ``module-type: syncadaptor`` provides functionality to get a list of tiddlers (this list is provided as ~SkinnyTiddlers, which are normal tiddlers without the text field) and to load, save and delete single tiddlers. A syncadaptor can also provide functions to login and logout so that syncadaptor modules can be used to synchronize tiddlers with a remote server.
|
A module with ``module-type: syncadaptor`` provides functionality to get a list of tiddlers (this list is provided as ~SkinnyTiddlers, which are normal tiddlers without the text field) and to load, save and delete single tiddlers. A syncadaptor can also provide functions to login and logout so that syncadaptor modules can be used to synchronize tiddlers with a remote server.
|
||||||
|
|
||||||
The syncer module only uses one syncadaptor and honours a special [[system tiddler|System Tiddlers]] [[$:/config/SyncFilter]] containing a [[filter string|Tags and Filter Mechanism]]. Tiddlers matching this filter string are not saved to the server with a syncadapter. It uses the [[WebServer API|https://tiddlywiki.com/#WebServer%20API%3A%20Get%20All%20Tiddlers]] to load modified tiddlers from the server, which returns only non-system tiddlers.
|
The syncer module only uses one syncadaptor and honours a special [[system tiddler|System Tiddlers]] [[$:/config/SyncFilter]] containing a [[filter string|Tags and Filter Mechanism]]. Tiddlers matching this filter string are saved to the server with a syncadapter. It uses the [[WebServer API|https://tiddlywiki.com/#WebServer%20API%3A%20Get%20All%20Tiddlers]] to load modified tiddlers from the server, which returns only non-system tiddlers.
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
created: 20180702160923664
|
created: 20180702160923664
|
||||||
modified: 20180703100549667
|
modified: 20211111023610539
|
||||||
tags: [[WebServer Guides]]
|
tags: [[WebServer Guides]]
|
||||||
title: Using HTTPS
|
title: Using HTTPS
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
By default, TiddlyWiki's WebServer serves resources over the insecure HTTP protocol. The risk is minimal if it is only being used within a private, trusted network but in many situations it is desirable to use a secure HTTPS connection.
|
By default, TiddlyWiki's WebServer serves resources over the insecure HTTP protocol. The risk is minimal if it is only being used within a private, trusted network but in many situations it is desirable to use a secure HTTPS connection.
|
||||||
|
|
||||||
HTTPS requires the server to be configured with a certificate via a "cert" file and a "key" file, configured via the [[tls-cert|WebServer Parameter: tls-cert]] and [[tls-key|WebServer Parameter: tls-key]] parameters
|
HTTPS requires the server to be configured with a certificate via a "cert" file and a "key" file, configured via the [[tls-cert|WebServer Parameter: tls-cert]] and [[tls-key|WebServer Parameter: tls-key]] parameters.
|
||||||
|
|
||||||
|
The optional [[tls-passphrase|WebServer Parameter: tls-passphrase]] parameter allows the server to use certificate files that have been generated with a passphrase/password.
|
||||||
|
|
||||||
Certificates can be obtained from a certification authority such as https://letsencrypt.org/, or you can create a self-signed certificate for internal testing.
|
Certificates can be obtained from a certification authority such as https://letsencrypt.org/, or you can create a self-signed certificate for internal testing.
|
||||||
|
|
||||||
@@ -17,3 +19,16 @@ openssl req -newkey rsa:2048 -new -nodes -keyout mywikifolder/key.pem -out mywik
|
|||||||
openssl x509 -req -days 365 -in mywikifolder/csr.pem -signkey mywikifolder/key.pem -out mywikifolder/server.crt
|
openssl x509 -req -days 365 -in mywikifolder/csr.pem -signkey mywikifolder/key.pem -out mywikifolder/server.crt
|
||||||
tiddlywiki mywikifolder --listen username=joe password=bloggs tls-key=key.pem tls-cert=server.crt
|
tiddlywiki mywikifolder --listen username=joe password=bloggs tls-key=key.pem tls-cert=server.crt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If using a [[tls-passphrase|WebServer Parameter: tls-passphrase]] to generate the certificate files, the commands would change as below:
|
||||||
|
|
||||||
|
* remove the `-nodes` flag, which specifies "no encryption"
|
||||||
|
* replace `TLS_PASSPHRASE` in the `-passout` and `-passin` parameters in the below commands with your chosen string.
|
||||||
|
|
||||||
|
This is the simplest, but __least secure method,__ of passing a passphrase to the certificate utility. See [[this Stack Exchange anwser on openssl certificates|https://security.stackexchange.com/questions/106525/generate-csr-and-private-key-with-password-with-openssl]] and the [[openssl|https://www.openssl.org/docs/man1.0.2/man1/openssl.html]] and [[openssl-passphrase-options|https://www.openssl.org/docs/manmaster/man1/openssl-passphrase-options.html]] page in the openssl utility documentation.
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl req -newkey rsa:2048 -passout pass:TLS_PASSPHRASE -new -keyout mywikifolder/key.pem -out mywikifolder/csr.pem -passout pass:TLS_PASSPHRASE
|
||||||
|
openssl x509 -req -days 365 -in mywikifolder/csr.pem -signkey mywikifolder/key.pem -out mywikifolder/server.crt -passin pass:TLS_PASSPHRASE
|
||||||
|
tiddlywiki mywikifolder --listen username=joe password=bloggs tls-key=key.pem tls-cert=server.crt tls-passphrase=TLS_PASSPHRASE
|
||||||
|
```
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ In order to avoid denial of service attacks with malformed filters in the defaul
|
|||||||
To enable a particular filter, create a tiddler with the title "$:/config/Server/ExternalFilters/" concatenated with the filter text, and the text field set to "yes". For example, the TiddlyWeb plugin includes the following shadow tiddler to enable the filter that it requires:
|
To enable a particular filter, create a tiddler with the title "$:/config/Server/ExternalFilters/" concatenated with the filter text, and the text field set to "yes". For example, the TiddlyWeb plugin includes the following shadow tiddler to enable the filter that it requires:
|
||||||
|
|
||||||
```
|
```
|
||||||
title: $:/config/Server/ExternalFilters/[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]]
|
title: $:/config/Server/ExternalFilters/[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/library/sjcl.js]] -[[$:/core]]
|
||||||
text: yes
|
text: yes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
created: 20180630194006239
|
created: 20180630194006239
|
||||||
modified: 20180904174030250
|
modified: 20211122004159427
|
||||||
tags: WebServer
|
tags: WebServer
|
||||||
title: WebServer Authorization
|
title: WebServer Authorization
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
''Authorization'' is the process of determining which resources may be accessed by a particular user. It occurs after [[authentication|WebServer Authentication]] has determined the identity of the user. TiddlyWiki's WebServer implements a simple authorization scheme which permits independent control of who has read and write access to a wiki.
|
''Authorization'' is the process of determining which resources may be accessed by a particular user. It occurs after [[authentication|WebServer Authentication]] has determined the identity of the user. TiddlyWiki's WebServer implements a simple authorization scheme which permits independent control of who has administrator access to the server, and read and write access to a wiki.
|
||||||
|
|
||||||
The WebServer parameters [[readers|WebServer Parameter: readers]] and [[writers|WebServer Parameter: writers]] each contain a comma separated list of //principals// (which is to say, either usernames or certain special tokens) which should have read or write access respectively.
|
The WebServer parameters [[admin|WebServer Parameter: admin]], [[readers|WebServer Parameter: readers]] and [[writers|WebServer Parameter: writers]] each contain a comma separated list of //principals// (which is to say, either usernames or certain special tokens) which should have read or write access respectively.
|
||||||
|
|
||||||
The available special tokens are:
|
The available special tokens are:
|
||||||
|
|
||||||
* ''(anon)'' - indicates all anonymous users
|
* ''(anon)'' - indicates all anonymous users
|
||||||
* ''(authenticated)'' - indicates all authenticated users
|
* ''(authenticated)'' - indicates all authenticated users
|
||||||
|
|
||||||
|
!! Admin Functions
|
||||||
|
|
||||||
|
<<.tip"""The ''(anon)'' token is not valid for the [[admin|WebServer Parameter: admin]] parameter.""">>
|
||||||
|
|
||||||
|
At this time, no server functions are restricted to ''admin'' authorized users in the unmodified [[Tiddlywiki server|WebServer]]. Third party plugins can leverage this to restrict routes or commands to a subset of authorized users.
|
||||||
|
|
||||||
!! Read-only Mode
|
!! Read-only Mode
|
||||||
|
|
||||||
Read-only mode is engaged when the current user is not authorized to write to the current wiki.
|
Read-only mode is engaged when the current user is not authorized to write to the current wiki.
|
||||||
@@ -39,3 +45,9 @@ In the following example, read access is granted to all authenticated users, but
|
|||||||
```
|
```
|
||||||
tiddlywiki mywikifolder --listen credentials=myusers.csv "readers=(authenticated)" writers=mary
|
tiddlywiki mywikifolder --listen credentials=myusers.csv "readers=(authenticated)" writers=mary
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In the following example, read and write access is granted to all authenticated users, but only "mary" is granted admin access:
|
||||||
|
|
||||||
|
```
|
||||||
|
tiddlywiki mywikifolder --listen credentials=myusers.csv "readers=(authenticated)" "writers=(authenticated)" admin=mary
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
caption: admin
|
||||||
|
created: 20211111015634164
|
||||||
|
modified: 20211111023141767
|
||||||
|
tags: [[WebServer Parameters]]
|
||||||
|
title: WebServer Parameter: admin
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
The [[web server configuration parameter|WebServer Parameters]] ''admin'' is used to specify the security principals with administrator access to the [[WebServer]]. Does not accept the ''(anon)'' special token. See [[WebServer Authorization]] for more details.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
caption: required-plugins
|
||||||
|
created: 20211226160733000
|
||||||
|
modified: 20211226160754000
|
||||||
|
tags: [[WebServer Parameters]]
|
||||||
|
title: WebServer Parameter: required-plugins
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
The [[web server configuration parameter|WebServer Parameters]] ''required-plugins'' is used to specify the plugins required to start the [[WebServer]]. It take a comma seperated list of plugin titles. The WebServer will issue a warnign in the console if the required plugins are not loaded. This parameter defaults to `$:/plugins/tiddlywiki/filesystem,$:/plugins/tiddlywiki/tiddlyweb`.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
caption: tls-passphrase
|
||||||
|
created: 20211111004416873
|
||||||
|
modified: 20211111022120158
|
||||||
|
tags: [[WebServer Parameters]]
|
||||||
|
title: WebServer Parameter: tls-passphrase
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
The optional [[web server configuration parameter|WebServer Parameters]] ''tls-passphrase'' contains the "certificate passphrase", a string used to decrypt the certificate file used when running the web server under HTTPS.
|
||||||
|
|
||||||
|
See [[Using HTTPS]] for details.
|
||||||
Reference in New Issue
Block a user