Release version 1.8.0

This commit is contained in:
muxator 2019-12-07 18:56:41 +01:00
commit c8580a6dc1
23 changed files with 1168 additions and 647 deletions

3
.dockerignore Normal file
View file

@ -0,0 +1,3 @@
.hg
settings.json
src/node_modules

View file

@ -1,3 +1,7 @@
# 1.8
* SECURITY: change referrer policy so that Etherpad addresses aren't leaked when links are clicked (discussion: https://github.com/ether/etherpad-lite/pull/3636)
* SECURITY: set the "secure" flag for the session cookies when served over SSL. From now on it will not be possible to serve the same instance both in cleartext and over SSL
# 1.8-beta.1
* FEATURE: code was migrated to `async`/`await`, getting rid of a lot of callbacks (see https://github.com/ether/etherpad-lite/issues/3540)
* FEATURE: support configuration via environment variables

View file

@ -1,18 +1,12 @@
# Etherpad Lite Dockerfile
#
# https://github.com/ether/etherpad-docker
# https://github.com/ether/etherpad-lite
#
# Author: muxator
#
# Version 0.1
FROM node:10-buster-slim
LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
# git hash of the version to be built.
# If not given, build the latest development version.
ARG ETHERPAD_VERSION=develop
# plugins to install while building the container. By default no plugins are
# installed.
# If given a value, it has to be a space-separated, quoted list of plugin names.
@ -25,24 +19,20 @@ ARG ETHERPAD_PLUGINS=
# this can be done with build args (and is mandatory to build ARM version)
ENV NODE_ENV=development
# grab the ETHERPAD_VERSION tarball from github (no need to clone the whole
# repository)
RUN echo "Getting version: ${ETHERPAD_VERSION}" && \
curl \
--location \
--fail \
--silent \
--show-error \
--output /opt/etherpad-lite.tar.gz \
https://github.com/ether/etherpad-lite/archive/"${ETHERPAD_VERSION}".tar.gz && \
mkdir /opt/etherpad-lite && \
tar xf /opt/etherpad-lite.tar.gz \
--directory /opt/etherpad-lite \
--strip-components=1 && \
rm /opt/etherpad-lite.tar.gz
# Follow the principle of least privilege: run as unprivileged user.
#
# Running as non-root enables running this image in platforms like OpenShift
# that do not allow images running as root.
RUN useradd --uid 5001 --create-home etherpad
RUN mkdir /opt/etherpad-lite && chown etherpad:etherpad /opt/etherpad-lite
USER etherpad:etherpad
WORKDIR /opt/etherpad-lite
COPY --chown=etherpad:etherpad ./ ./
# install node dependencies for Etherpad
RUN bin/installDeps.sh && \
rm -rf ~/.npm/_cacache
@ -54,18 +44,7 @@ RUN bin/installDeps.sh && \
RUN for PLUGIN_NAME in ${ETHERPAD_PLUGINS}; do npm install "${PLUGIN_NAME}"; done
# Copy the configuration file.
COPY ./settings.json /opt/etherpad-lite/
# Follow the principle of least privilege: run as unprivileged user.
#
# Running as non-root enables running this image in platforms like OpenShift
# that do not allow images running as root.
RUN \
echo 'etherpad:x:65534:65534:etherpad:/:' > /etc/passwd && \
echo 'etherpad:x:65534:' > /etc/group && \
chown -R etherpad:etherpad ./
USER etherpad
COPY --chown=etherpad:etherpad ./settings.json.docker /opt/etherpad-lite/settings.json
EXPOSE 9001
CMD ["node", "node_modules/ep_etherpad-lite/node/server.js"]

View file

@ -1,4 +1,5 @@
# A real-time collaborative editor for the web
<a href="https://hub.docker.com/r/etherpad/etherpad"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/etherpad/etherpad"></a>
![Demo Etherpad Animated Jif](https://i.imgur.com/zYrGkg3.gif "Etherpad in action")
# About
@ -61,6 +62,10 @@ If cloning to a subdirectory within another project, you may need to do the foll
2. Edit the db `filename` in `settings.json` to the relative directory with the file (e.g. `application/lib/etherpad-lite/var/dirty.db`)
3. Add auto-generated files to the main project `.gitignore`
## Docker container
Find [here](doc/docker.md) information on running Etherpad in a container.
# Next Steps
## Tweak the settings

View file

@ -9,7 +9,7 @@ if [ -d "../bin" ]; then
fi
ignoreRoot=0
for ARG in $*
for ARG in "$@"
do
if [ "$ARG" = "--root" ]; then
ignoreRoot=1
@ -32,10 +32,10 @@ fi
rm -rf src/node_modules
#Prepare the environment
bin/installDeps.sh $* || exit 1
bin/installDeps.sh "$@" || exit 1
#Move to the node folder and start
echo "Started Etherpad..."
SCRIPTPATH=`pwd -P`
node "${SCRIPTPATH}/node_modules/ep_etherpad-lite/node/server.js" $*
node "${SCRIPTPATH}/node_modules/ep_etherpad-lite/node/server.js" "$@"

View file

@ -17,4 +17,4 @@ echo "Open 'chrome://inspect' on Chrome to start debugging."
#Use 0.0.0.0 to allow external connections to the debugger
#(ex: running Etherpad on a docker container). Use default port # (9229)
node --inspect=0.0.0.0:9229 node_modules/ep_etherpad-lite/node/server.js $*
node --inspect=0.0.0.0:9229 node_modules/ep_etherpad-lite/node/server.js "$@"

View file

@ -83,7 +83,7 @@ require_minimal_version "nodejs" "$NODE_VERSION_STRING" "$REQUIRED_NODE_MAJOR" "
#Get the name of the settings file
settings="settings.json"
a='';
for arg in $*; do
for arg in "$@"; do
if [ "$a" = "--settings" ] || [ "$a" = "-s" ]; then settings=$arg; fi
a=$arg
done

View file

@ -9,7 +9,7 @@ if [ -d "../bin" ]; then
fi
ignoreRoot=0
for ARG in $*
for ARG in "$@"
do
if [ "$ARG" = "--root" ]; then
ignoreRoot=1
@ -29,11 +29,11 @@ if [ "$(id -u)" -eq 0 ] && [ $ignoreRoot -eq 0 ]; then
fi
#Prepare the environment
bin/installDeps.sh $* || exit 1
bin/installDeps.sh "$@" || exit 1
#Move to the node folder and start
echo "Started Etherpad..."
SCRIPTPATH=`pwd -P`
exec node "$SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js" $*
exec node "$SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js" "$@"

View file

@ -1,79 +1,60 @@
# Docker image
# Docker
This directory contains the files that are used to build the official Docker image on https://hub.docker.com/r/etherpad/etherpad.
The official Docker image is available on https://hub.docker.com/r/etherpad/etherpad.
# Downloading from Docker Hub
## Downloading from Docker Hub
If you are ok downloading a [prebuilt image from Docker Hub](https://hub.docker.com/r/etherpad/etherpad), these are the commands:
```bash
# gets the latest published version
docker pull etherpad/etherpad
# gets a specific version
docker pull etherpad/etherpad:1.7.5
docker pull etherpad/etherpad:1.8.0
```
# Build a personalized container
## Build a personalized container
If you want to use a personalized settings file, **you will have to rebuild your image**.
All of the following instructions are as a member of the `docker` group.
## Rebuilding with custom settings
Prepare your custom `settings.json` file:
```bash
cd <BASEDIR>/docker
cp ../settings.json.template settings.json
[ further edit your settings.json as needed]
```
### Rebuilding with custom settings
Edit `<BASEDIR>/settings.json.docker` at your will. When rebuilding the image, this file will be copied inside your image and renamed to `setting.json`.
**Each configuration parameter can also be set via an environment variable**, using the syntax `"${ENV_VAR}"` or `"${ENV_VAR:default_value}"`. For details, refer to `settings.json.template`.
## Rebuilding including some plugins
### Rebuilding including some plugins
If you want to install some plugins in your container, it is sufficient to list them in the ETHERPAD_PLUGINS build variable.
The variable value has to be a space separated, double quoted list of plugin names (see examples).
Some plugins will need personalized settings in the `settings.json` file. Just refer to the previous section, and include them in your custom `settings.json`.
Some plugins will need personalized settings. Just refer to the previous section, and include them in your custom `settings.json.docker`.
## Examples
### Examples
Build the latest development version:
Build a Docker image from the currently checked-out code:
```bash
docker build --tag <YOUR_USERNAME>/etherpad .
```
Build the latest stable version:
```bash
docker build --build-arg ETHERPAD_VERSION=master --build-arg NODE_ENV=production --tag <YOUR_USERNAME>/etherpad .
```
Build a specific tagged version:
```bash
docker build --build-arg ETHERPAD_VERSION=1.7.5 --build-arg NODE_ENV=production --tag <YOUR_USERNAME>/etherpad .
```
Build a specific git hash:
```bash
docker build --build-arg ETHERPAD_VERSION=4c45ac3cb1ae --tag <YOUR_USERNAME>/etherpad .
```
Include two plugins in the container:
```bash
docker build --build-arg ETHERPAD_PLUGINS="ep_codepad ep_author_neat" --tag <YOUR_USERNAME>/etherpad .
```
# Running your instance:
## Running your instance:
To run your instance:
```bash
docker run --detach --publish <DESIDERED_PORT>:9001 <YOUR_USERNAME>/etherpad
docker run --detach --publish <DESIRED_PORT>:9001 <YOUR_USERNAME>/etherpad
```
And point your browser to `http://<YOUR_IP>:<DESIDERED_PORT>`
And point your browser to `http://<YOUR_IP>:<DESIRED_PORT>`
# Options available by default
## Options available by default
The `settings.json` available by default enables some configuration to be set from the environment.
The `settings.json.docker` available by default enables some configuration to be set from the environment.
Available options:
* `TITLE`: The name of the instance
* `FAVICON`: favicon default name, or a fully specified URL to your own favicon
* `SKIN_NAME`: either `no-skin`, `colibris` or an existing directory under `src/static/skins`.
@ -90,9 +71,10 @@ Available options:
* `DB_FILENAME`: in case `DB_TYPE` is `DirtyDB`, the database filename. Default: `var/dirty.db`
* `ADMIN_PASSWORD`: the password for the `admin` user (leave unspecified if you do not want to create it)
* `USER_PASSWORD`: the password for the first user `user` (leave unspecified if you do not want to create it)
* `TRUST_PROXY`: set to `true` if you are using a reverse proxy in front of Etherpad (for example: Traefik for SSL termination via Let's Encrypt). This will affect security and correctness of the logs if not done
* `LOGLEVEL`: valid values are `DEBUG`, `INFO`, `WARN` and `ERROR`
## Examples
### Examples
Use a Postgres database, no admin user enabled:

View file

@ -1,6 +1,7 @@
@include documentation
@include stats
@include localization
@include docker
@include skins
@include api/api
@include plugins

View file

@ -1,3 +1,12 @@
/**
* THIS IS THE SETTINGS FILE THAT IS COPIED INSIDE THE DOCKER CONTAINER.
*
* By default, some runtime customizations are supported (see the
* documentation).
*
* If you need more control, edit this file and rebuild the container.
*/
/*
* This file must be valid JSON. But comments are allowed
*
@ -278,8 +287,14 @@
/*
* When you use NGINX or another proxy/load-balancer set this to true.
*
* This is especially necessary when the reverse proxy performs SSL
* termination, otherwise the cookies will not have the "secure" flag.
*
* The other effect will be that the logs will contain the real client's IP,
* instead of the reverse proxy's IP.
*/
"trustProxy": false,
"trustProxy": "${TRUST_PROXY:false}",
/*
* Privacy: disable IP logging

View file

@ -290,6 +290,12 @@
/*
* When you use NGINX or another proxy/load-balancer set this to true.
*
* This is especially necessary when the reverse proxy performs SSL
* termination, otherwise the cookies will not have the "secure" flag.
*
* The other effect will be that the logs will contain the real client's IP,
* instead of the reverse proxy's IP.
*/
"trustProxy": false,

View file

@ -8,7 +8,8 @@
"Santhosh.thottingal",
"Nesi",
"Jinoytommanjaly",
"Ambadyanands"
"Ambadyanands",
"Adithyak1997"
]
},
"index.newPad": "പുതിയ പാഡ്",
@ -93,6 +94,7 @@
"pad.chat": "തത്സമയസംവാദം",
"pad.chat.title": "ഈ പാഡിന്റെ തത്സമയസംവാദം തുറക്കുക.",
"pad.chat.loadmessages": "കൂടുതൽ സന്ദേശങ്ങൾ എടുക്കുക",
"pad.chat.writeMessage.placeholder": "താങ്കളുടെ സന്ദേശങ്ങൾ ഇവിടെ കുറിക്കുക",
"timeslider.pageTitle": "{{appTitle}} സമയരേഖ",
"timeslider.toolbar.returnbutton": "പാഡിലേക്ക് മടങ്ങുക",
"timeslider.toolbar.authors": "രചയിതാക്കൾ:",

View file

@ -76,6 +76,15 @@ exports.restartServer = function () {
// https://github.com/ether/etherpad-lite/issues/2547
res.header("X-UA-Compatible", "IE=Edge,chrome=1");
// Enable a strong referrer policy. Same-origin won't drop Referers when
// loading local resources, but it will drop them when loading foreign resources.
// It's still a last bastion of referrer security. External URLs should be
// already marked with rel="noreferer" and user-generated content pages are already
// marked with <meta name="referrer" content="no-referrer">
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
// https://github.com/ether/etherpad-lite/pull/3636
res.header("Referrer-Policy", "same-origin");
// send git version in the Server response header if exposeVersion is true.
if (settings.exposeVersion) {
res.header("Server", serverName);

View file

@ -16,7 +16,28 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
var io = socketio({
transports: settings.socketTransportProtocols
}).listen(args.server);
}).listen(args.server, {
/*
* Do not set the "io" cookie.
*
* The "io" cookie is created by socket.io, and its purpose is to offer an
* handle to perform load balancing with session stickiness when the library
* falls back to long polling or below.
*
* In Etherpad's case, if an operator needs to load balance, he can use the
* "express_sid" cookie, and thus "io" is of no use.
*
* Moreover, socket.io API does not offer a way of setting the "secure" flag
* on it, and thus is a liability.
*
* Let's simply nuke "io".
*
* references:
* https://socket.io/docs/using-multiple-nodes/#Sticky-load-balancing
* https://github.com/socketio/socket.io/issues/2276#issuecomment-147184662 (not totally true, actually, see above)
*/
cookie: false,
});
/* Require an express session cookie to be present, and load the
* session. See http://www.danielbaulig.de/socket-ioexpress for more

View file

@ -45,7 +45,24 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// Or if language cookie doesn't exist
if (req.cookies.language === undefined)
{
res.cookie('language', settings.padOptions.lang);
cookieOptions = {
/* req.protocol may be 'https' because either:
*
* 1. we are directly serving the nodejs application over SSL, using
* the "ssl" options in settings.json
*
* 2. we are serving the nodejs application in plaintext, but we are
* using a reverse proxy that terminates SSL for us. In this case,
* the user has to set trustProxy = true in settings.json, and thus
* req.protocol will reflect the value of the X-Forwarded-Proto HTTP
* header
*
* Please note that this will not be compatible with applications being
* served over http and https at the same time.
*/
secure: (req.protocol === 'https'),
}
res.cookie('language', settings.padOptions.lang, cookieOptions);
}
// The below might break for pads being rewritten

View file

@ -123,7 +123,37 @@ exports.expressConfigure = function (hook_name, args, cb) {
}
args.app.sessionStore = exports.sessionStore;
args.app.use(sessionModule({secret: exports.secret, store: args.app.sessionStore, resave: true, saveUninitialized: true, name: 'express_sid', proxy: true, cookie: { secure: !!settings.ssl }}));
args.app.use(sessionModule({
secret: exports.secret,
store: args.app.sessionStore,
resave: true,
saveUninitialized: true,
name: 'express_sid',
proxy: true,
cookie: {
/*
* The automatic express-session mechanism for determining if the
* application is being served over ssl is similar to the one used for
* setting the language cookie, which check if one of these conditions is
* true:
*
* 1. we are directly serving the nodejs application over SSL, using the
* "ssl" options in settings.json
*
* 2. we are serving the nodejs application in plaintext, but we are using
* a reverse proxy that terminates SSL for us. In this case, the user
* has to set trustProxy = true in settings.json, and the information
* wheter the application is over SSL or not will be extracted from the
* X-Forwarded-Proto HTTP header
*
* Please note that this will not be compatible with applications being
* served over http and https at the same time.
*
* reference: https://github.com/expressjs/session/blob/v1.17.0/README.md#cookiesecure
*/
secure: 'auto',
}
}));
args.app.use(cookieParser(settings.sessionKey, {}));

View file

@ -285,7 +285,14 @@ function getHTMLFromAtext(pad, atext, authorColors)
var url = urlData[1];
var urlLength = url.length;
processNextChars(startIndex - idx);
assem.append('<a href="' + Security.escapeHTMLAttribute(url) + '">');
// Using rel="noreferrer" stops leaking the URL/location of the exported HTML when clicking links in the document.
// Not all browsers understand this attribute, but it's part of the HTML5 standard.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer
// Additionally, we do rel="noopener" to ensure a higher level of referrer security.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
// https://mathiasbynens.github.io/rel-noopener/
// https://github.com/ether/etherpad-lite/pull/3636
assem.append('<a href="' + Security.escapeHTMLAttribute(url) + '" rel="noreferrer noopener">');
processNextChars(urlLength);
assem.append('</a>');
});

1533
src/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,7 @@
"log4js": "0.6.35",
"measured-core": "1.11.2",
"nodeify": "^1.0.1",
"npm": "6.12.1",
"npm": "6.13.1",
"object.values": "^1.0.4",
"request": "2.88.0",
"resolve": "1.1.7",
@ -84,6 +84,6 @@
"scripts": {
"test": "nyc mocha --timeout 5000 ../tests/backend/specs/api"
},
"version": "1.8.0-beta.1",
"version": "1.8.0",
"license": "Apache-2.0"
}

View file

@ -198,7 +198,14 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
{
href = "http://"+href;
}
extraOpenTags = extraOpenTags + '<a href="' + Security.escapeHTMLAttribute(href) + '">';
// Using rel="noreferrer" stops leaking the URL/location of the pad when clicking links in the document.
// Not all browsers understand this attribute, but it's part of the HTML5 standard.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer
// Additionally, we do rel="noopener" to ensure a higher level of referrer security.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
// https://mathiasbynens.github.io/rel-noopener/
// https://github.com/ether/etherpad-lite/pull/3636
extraOpenTags = extraOpenTags + '<a href="' + Security.escapeHTMLAttribute(href) + '" rel="noreferrer noopener">';
extraCloseTags = '</a>' + extraCloseTags;
}
if (simpleTags)

View file

@ -223,7 +223,14 @@ var padutils = {
var startIndex = urls[j][0];
var href = urls[j][1];
advanceTo(startIndex);
pieces.push('<a ', (target ? 'target="' + Security.escapeHTMLAttribute(target) + '" ' : ''), 'href="', Security.escapeHTMLAttribute(href), '">');
// Using rel="noreferrer" stops leaking the URL/location of the pad when clicking links in the document.
// Not all browsers understand this attribute, but it's part of the HTML5 standard.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer
// Additionally, we do rel="noopener" to ensure a higher level of referrer security.
// https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
// https://mathiasbynens.github.io/rel-noopener/
// https://github.com/ether/etherpad-lite/pull/3636
pieces.push('<a ', (target ? 'target="' + Security.escapeHTMLAttribute(target) + '" ' : ''), 'href="', Security.escapeHTMLAttribute(href), '" rel="noreferrer noopener">');
advanceTo(startIndex + href.length);
pieces.push('</a>');
}

View file

@ -360,9 +360,13 @@
<% e.end_block(); %>
<% e.begin_block("scripts"); %>
<script type="text/javascript">
var padutils = require('../static/js/pad_utils').padutils;
<script type="text/javascript" src="../static/js/require-kernel.js"></script>
<!-- Include pad_utils manually -->
<script type="text/javascript" src="../javascripts/lib/ep_etherpad-lite/static/js/pad_utils.js?callback=require.define"></script>
<script type="text/javascript">
// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7&dn=apache-2.0.txt
(function() {
// Display errors on page load to the user
@ -380,7 +384,6 @@
// @license-end
</script>
<script type="text/javascript" src="../static/js/require-kernel.js"></script>
<script type="text/javascript" src="../socket.io/socket.io.js"></script>
<!-- Include base packages manually (this help with debugging) -->