diff --git a/CHANGELOG.md b/CHANGELOG.md index 86b4051..4ab3910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## v1.3.2 + +Release date: *2024-06-13* + +Add the build instructions for a standalone Docker image (for demo purposes). +Fix a vulnerability alert on `braces` ([GHSA-grv7-fg5c-xmjg](https://github.com/advisories/GHSA-grv7-fg5c-xmjg)). + ## v1.3.1 diff --git a/docs/damastversion.sty b/docs/damastversion.sty index 6dc6589..5dbf854 100644 --- a/docs/damastversion.sty +++ b/docs/damastversion.sty @@ -1 +1 @@ -\newcommand\damastversion{v1.3.1} +\newcommand\damastversion{v1.3.2} diff --git a/documentation.pdf b/documentation.pdf index e99abab..2ec1c4a 100644 Binary files a/documentation.pdf and b/documentation.pdf differ diff --git a/package-lock.json b/package-lock.json index 0603a7c..3efcb9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "damast", - "version": "1.3.1", + "version": "1.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "damast", - "version": "1.3.1", + "version": "1.3.2", "license": "MIT", "dependencies": { "@cfworker/json-schema": "^1.8.0", @@ -1647,12 +1647,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2924,9 +2924,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" diff --git a/package.json b/package.json index 166f044..4cb2de6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "damast", - "version": "1.3.1", + "version": "1.3.2", "description": "", "main": "webpack.config.js", "scripts": { diff --git a/util/standalone-docker-image/.gitignore b/util/standalone-docker-image/.gitignore new file mode 100644 index 0000000..0b2a122 --- /dev/null +++ b/util/standalone-docker-image/.gitignore @@ -0,0 +1,2 @@ +/damast/ +/download-and-extract-tiles.sh.gz diff --git a/util/standalone-docker-image/Dockerfile b/util/standalone-docker-image/Dockerfile new file mode 100644 index 0000000..3915153 --- /dev/null +++ b/util/standalone-docker-image/Dockerfile @@ -0,0 +1,141 @@ +FROM continuumio/miniconda3:4.10.3 + +LABEL maintainer="Max Franke " + +RUN conda install -c conda-forge cartopy + +ENV TZ="Europe/Berlin" +ENV DEBIAN_FRONTEND="noninteractive" + +ARG USER_ID +ARG GROUP_ID +ENV USER_ID=1000 +ENV GROUP_ID=1000 + +RUN addgroup --gid $GROUP_ID www +RUN adduser \ + --disabled-password \ + --home /www \ + --gecos '' \ + --uid $USER_ID \ + --gid $GROUP_ID www + +RUN apt-get update && apt-get install -y apt-utils build-essential + +# configure timezone +RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime && \ + apt-get install -y tzdata + +# install xelatex stuff +RUN apt-get install -y \ + texlive-base \ + texlive-xetex \ + texlive-lang-arabic \ + fonts-freefont-ttf \ + fonts-noto-core \ + fontconfig \ + zip + +# configure latex +RUN echo 'main_memory = 9000000\nextra_mem_top = 6000000\nextra_mem_bot = 6000000\nhash_extra = 200000\npool_size = 3850000' >> /etc/texmf/web2c/texmf.cnf + + +# get and install Syriac font +WORKDIR /tmp +RUN wget http://bethmardutho.org/wp-content/uploads/2018/06/melthofonts-1.zip \ + && unzip melthofonts-1.zip \ + && cp melthofonts-1/melthofonts-1.21/SyrCOMTalada.otf /usr/share/fonts/ \ + && fc-cache -f -v \ + && rm -rf melthofonts-1.zip melthofonts-1 + +# install en_US locale +RUN apt-get install -y locales \ + && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \ + && locale-gen + +# install postgresql stuff +RUN apt-get install -y postgresql-client postgresql-11 postgresql-11-postgis-2.5 + +# configure postgresql +RUN mkdir -p /usr/local/pgsql/data +RUN chown -R postgres:postgres /usr/local/pgsql/data +RUN chmod ug+s /usr/local/pgsql/data + +RUN su postgres -c "/usr/lib/postgresql/11/bin/initdb -D /usr/local/pgsql/data" + +# copy launch scripts +COPY start-postgres-server.sh run.sh start-damast.sh / + +# download database dump +RUN wget \ + -O damast-database-dump.sql \ + "https://darus.uni-stuttgart.de/api/access/datafile/:persistentId?persistentId=doi:10.18419/darus-2318/4" +RUN bash -c 'echo -e "80c80a5d656856bf0c1b016bd988f2df\tdamast-database-dump.sql" | md5sum -c -' + +# create DB users, Damast DB users, database, load dump +RUN su postgres -c /start-postgres-server.sh \ + && psql -U postgres -h localhost -c "CREATE USER users; CREATE USER api PASSWORD 'apipassword'; CREATE USER ro_dump; CREATE USER damast; GRANT users TO damast;" \ + && psql -U postgres -h localhost -c "CREATE DATABASE ocn;" \ + && psql -U postgres -h localhost -d ocn -f damast-database-dump.sql \ + && psql -U postgres -h localhost -d ocn -c "INSERT INTO users (name, comment) VALUES ('damast', 'default user');" + + +# install and configure nginx +RUN apt-get install -y nginx curl +# configure nginx with a template so that the port can be changed dynamically +# via the NGINX_PORT and DAMAST_PORT environment variables during "docker run" +COPY nginx_default.conf.template /etc/nginx/templates/default.conf.template + +# download shaded relief tiles +COPY download-and-extract-tiles.sh.gz /tmp +RUN zcat /tmp/download-and-extract-tiles.sh.gz | /bin/bash - + +# data directory +RUN mkdir /data && chown www:www /data && chmod gu+s /data + +# install Python dependencies +USER www + +RUN pip install --no-warn-script-location \ + 'flask==2.3.2' \ + 'gunicorn[gevent]' \ + 'requests' \ + 'Flask-HTTPAuth' \ + 'passlib[bcrypt]' \ + 'pyjwt>=2' \ + 'pyyaml' \ + 'postgres' \ + 'password-strength' \ + 'brotli' \ + 'apscheduler' \ + 'html5lib' \ + 'jsonschema==3.2.0' \ + 'python-dateutil' \ + 'beautifulsoup4' \ + 'Shapely==1.8a3' \ + 'geopandas' \ + 'geoplot' \ + 'pygeos' \ + 'python-Levenshtein' + +WORKDIR / + +# files +COPY ./damast /damast + +ARG DAMAST_PORT +ENV DAMAST_VERSION="v1.3.2" +ENV DAMAST_ENVIRONMENT="PRODUCTION" +ENV DAMAST_PORT="8000" + +# copy configuration stuff +ENV DAMAST_CONFIG=/data/damast.config.json +COPY damast.config.json /data/damast.config.json +COPY users_db.sql /tmp +RUN sqlite3 /data/users.db < /tmp/users_db.sql + +# cleanup, copy launch scripts +USER root +RUN rm -r /tmp/users_db.sql /tmp/download-and-extract-tiles.sh.gz /tmp/damast-database-dump.sql /tmp/tile-download + +CMD /run.sh diff --git a/util/standalone-docker-image/README.md b/util/standalone-docker-image/README.md new file mode 100644 index 0000000..d7d4361 --- /dev/null +++ b/util/standalone-docker-image/README.md @@ -0,0 +1,5 @@ +# Standalone Docker Image + +This is the build files for a standalone Docker image. +This image is for demonstration purposes only. +**Do not use this for a production environment!** diff --git a/util/standalone-docker-image/build-docker-image.sh b/util/standalone-docker-image/build-docker-image.sh new file mode 100755 index 0000000..8279a0c --- /dev/null +++ b/util/standalone-docker-image/build-docker-image.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +damast_version="${1:-1.3.2}" + +echo "Building Damast image (version $damast_version)" +echo + +echo "Clean-building source files" +( + cd ../.. + make clean + make prod +) + +echo "Copying in tile download script" +cp ../shaded-relief-map-tiles/download_and_extract.sh.gz download-and-extract-tiles.sh.gz + +echo "Copying in Damast files" +cp -r ../../damast . + +echo "Building image" +sudo docker build -t "damast-standalone:$damast_version" . diff --git a/util/standalone-docker-image/damast.config.json b/util/standalone-docker-image/damast.config.json new file mode 100644 index 0000000..63278dd --- /dev/null +++ b/util/standalone-docker-image/damast.config.json @@ -0,0 +1,12 @@ +{ + "pgpassword": "apipassword", + "report_file": "/data/reports.db", + "access_log": "/data/access_log", + "error_log": "/data/error_log", + "environment": "PRODUCTION", + "proxycount": 1, + "proxyprefix": "/", + "override_path": "/data/override", + "annotation_suggestion_rebuild": 1, + "map_tile_path": "/tiles/{z}/{x}/{y}.png" +} \ No newline at end of file diff --git a/util/standalone-docker-image/nginx_default.conf.template b/util/standalone-docker-image/nginx_default.conf.template new file mode 100644 index 0000000..8bf3afc --- /dev/null +++ b/util/standalone-docker-image/nginx_default.conf.template @@ -0,0 +1,34 @@ +server { + listen @NGINX_PORT@ default_server; + listen [::]:@NGINX_PORT@ default_server; + + # shaded relief map tiles + location /tiles { + root /var/www/html; + error_page 404 /__empty-error-page__.html; + try_files $uri =404; + add_header X-file-copyright "Tile data (c) Max Franke 2024. https://doi.org/10.18419/darus-3837"; + } + + location = /__empty-error-page__.html { + internal; + return 200 ""; + } + + + location / { + proxy_pass http://localhost:@DAMAST_PORT@/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Prefix /; + proxy_set_header X-Forwarded-Proto $scheme; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} \ No newline at end of file diff --git a/util/standalone-docker-image/run.sh b/util/standalone-docker-image/run.sh new file mode 100755 index 0000000..d6c8019 --- /dev/null +++ b/util/standalone-docker-image/run.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +set -eu + +if test "$(whoami)" "!=" "root" +then + echo "Error: $0 must be started under the 'root' user!" + exit 1 +fi + +# decide which port to run nginx and Damast on via environment variables +port=${NGINX_PORT:-80} +damastport=${DAMAST_PORT:-8000} + +if test "$damastport" "=" "$port" +then + echo "Warning: nginx is set to run on the same port as Damast ($DAMAST_PORT). Changing Damast to run on port 8001 instead." + DAMAST_PORT=8001 + damastport=${DAMAST_PORT:-8001} + export DAMAST_PORT +fi + +sed "s/@NGINX_PORT@/$port/g;s/@DAMAST_PORT@/$damastport/g" /etc/nginx/templates/default.conf.template > /etc/nginx/sites-available/default + +echo "Starting nginx on [::]:$port" +nginx +echo + +su postgres -c /start-postgres-server.sh +echo + +su www -c /start-damast.sh \ No newline at end of file diff --git a/util/standalone-docker-image/start-damast.sh b/util/standalone-docker-image/start-damast.sh new file mode 100755 index 0000000..4d0288f --- /dev/null +++ b/util/standalone-docker-image/start-damast.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +set -eu + +if test "$(whoami)" "!=" "www" +then + echo "Error: $0 must be started under the 'www' user!" + exit 1 +fi + +cat <<-EOF +Starting Damast Flask server on [::]:$DAMAST_PORT (inside of Docker container) ... + +Damast will be available through the nginx reverse proxy on [::]:${NGINX_PORT:-80} as well. +This address and port should be exposed to the outside of the container (by +passing "-p ${NGINX_PORT:-80}:${NGINX_PORT:-80}" to "docker run") to ensure that all internal links and +redirects work as desired. The internal nginx port can be changed through the +environment variable NGINX_PORT, and is 80 by default. To change it, pass the +new value to "docker run" as "-e NGINX_PORT=. + +Keep in mind that the respective port should be exposed outside of the +container with the "-p :" flag as well. The internal and +external flag MUST match so that redirects and internal links in Damast work +properly. Mapping the internal port to a different external port will break +already on the redirect to the login page. + +The internal port for the Damast Flask server can be exposed as well. This will +break the map tiles hosted via the internal nginx server, but otherwise work. +By default, the Flask server listens on [::]:8000. This can be changed by +setting a new port via "-e DAMAST_PORT=". Note that if the nginx and +Damast internal ports are the same, the Damast port is changed to 8001. +EOF + +/usr/bin/env python3 \ + -m gunicorn \ + -b "[::]:$DAMAST_PORT" \ + 'damast:create_app()' \ + --worker-class=gevent \ + --workers=1 \ + --threads=4 \ + --timeout 0 \ No newline at end of file diff --git a/util/standalone-docker-image/start-postgres-server.sh b/util/standalone-docker-image/start-postgres-server.sh new file mode 100755 index 0000000..a363205 --- /dev/null +++ b/util/standalone-docker-image/start-postgres-server.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -eu + +if test "$(whoami)" "!=" "postgres" +then + echo "Error: $0 must be started under the 'postgres' user!" + exit 1 +fi + +nohup /usr/lib/postgresql/11/bin/postgres -D /usr/local/pgsql/data > /tmp/postgresql.log & +echo "Started PostgreSQL 11 server" + +while ! pg_isready -h localhost +do + sleep 1 +done \ No newline at end of file diff --git a/util/standalone-docker-image/users_db.sql b/util/standalone-docker-image/users_db.sql new file mode 100644 index 0000000..685e8a2 --- /dev/null +++ b/util/standalone-docker-image/users_db.sql @@ -0,0 +1,15 @@ +CREATE TABLE users ( + id TEXT PRIMARY KEY NOT NULL CHECK(id <> 'visitor'), + password TEXT NOT NULL, + expires DATE DEFAULT NULL, + roles TEXT NOT NULL DEFAULT '', + comment TEXT DEFAULT NULL +); + +INSERT INTO users VALUES ( + 'damast', + '$5$rounds=535000$FjT0JOkRfzFieD/E$E7dz20Q9S6H2xjCizWaCg//JWep0O0HZBeprkLlEfe8', + NULL, + 'user,dev,annotator,vis,geodb,reporting,readdb,writedb', + 'default user, password "damast"' +) \ No newline at end of file