From 5d70c5e06332e1473bb9c47dc2d60843b96d808f Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 4 Jan 2024 17:36:44 +0100 Subject: [PATCH 01/85] add hetzner_cloud deployment folder, simplify config --- deployment/bare_metal/.env.dist | 117 ++++++++-------- deployment/bare_metal/doc/server.drawio | 118 ++++++++++++++++ .../sites-available/gradido.conf.ssl.template | 128 ------------------ .../sites-available/gradido.conf.template | 2 +- .../update-page.conf.ssl.template | 37 ----- deployment/bare_metal/start.sh | 8 +- deployment/hetzner_cloud/README.md | 82 +++++++++++ deployment/hetzner_cloud/cloudConfig.yaml | 46 +++++++ deployment/hetzner_cloud/install.sh | 60 ++++++++ deployment/hetzner_cloud/mysql_secure.sh | 33 +++++ nginx/gradido.conf | 2 +- 11 files changed, 403 insertions(+), 230 deletions(-) create mode 100644 deployment/bare_metal/doc/server.drawio delete mode 100644 deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template delete mode 100644 deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template create mode 100644 deployment/hetzner_cloud/README.md create mode 100644 deployment/hetzner_cloud/cloudConfig.yaml create mode 100644 deployment/hetzner_cloud/install.sh create mode 100644 deployment/hetzner_cloud/mysql_secure.sh diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 1335e06a5..9abc739fb 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -1,45 +1,25 @@ -GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log - -# start script -DEPLOY_SEED_DATA=false - -# nginx -NGINX_REWRITE_LEGACY_URLS=true -NGINX_SSL=true -NGINX_SERVER_NAME=stage1.gradido.net -NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem -NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem -NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem -NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf -NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page - -# webhook -WEBHOOK_GITHUB_SECRET=secret -WEBHOOK_GITHUB_BRANCH=master - -# community -COMMUNITY_NAME="Gradido Development Stage1" -COMMUNITY_URL=https://stage1.gradido.net/ -COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register -COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} -COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" +# Need to adjust! +COMMUNITY_NAME="Your community name" +COMMUNITY_DESCRIPTION="Short Description from your Community." +COMMUNITY_URL=gddhost.tld COMMUNITY_SUPPORT_MAIL=support@supportmail.com -# backend +# Need to adjust by updates +# config versions +DATABASE_CONFIG_VERSION=v1.2022-03-18 BACKEND_CONFIG_VERSION=v17.2023-07-03 +FRONTEND_CONFIG_VERSION=v4.2022-12-20 +ADMIN_CONFIG_VERSION=v1.2022-03-18 +FEDERATION_CONFIG_VERSION=v1.2023-01-09 +FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 -JWT_EXPIRES_IN=10m -GDT_API_URL=https://gdt.gradido.net - -TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log - -KLICKTIPP=false -KLICKTIPP_USER= -KLICKTIPP_PASSWORD= -KLICKTIPP_APIKEY_DE= -KLICKTIPP_APIKEY_EN= +# Need adjustments for test system +URL_PROTOCOL=https +# start script +# only for test server +DEPLOY_SEED_DATA=false +# setup email account for sending gradido system messages to users EMAIL=true EMAIL_TEST_MODUS=false EMAIL_TEST_RECEIVER=test_team@gradido.net @@ -47,41 +27,57 @@ EMAIL_USERNAME=peter@lustig.de EMAIL_SENDER=peter@lustig.de EMAIL_PASSWORD=1234 EMAIL_SMTP_URL=smtp.lustig.de -EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=https://stage1.gradido.net/forgot-password -EMAIL_LINK_OVERVIEW=https://stage1.gradido.net/overview EMAIL_CODE_VALID_TIME=1440 EMAIL_CODE_REQUEST_TIME=10 -WEBHOOK_ELOPAGE_SECRET=secret +# Logging +GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log +TYPEORM_LOGGING_RELATIVE_PATH=/home/gradido/gradido/deployment/bare_metal/log/typeorm.backend.log + +# webhook +WEBHOOK_GITHUB_SECRET=secret +WEBHOOK_GITHUB_BRANCH=master + +# frontend and admin paths, usually don't need changes +# used in nginx config and for links in emails +WALLET_PATH=/login +COMMUNITY_REGISTER_PATH=/register +COMMUNITY_REDEEM_PATH=/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code} +WALLET_AUTH_PATH=/authenticate?token={token} +EMAIL_LINK_VERIFICATION=/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD=/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD=/forgot-password +EMAIL_LINK_OVERVIEW=/overview +ADMIN_AUTH_PATH=/admin/authenticate?token={token} +GRAPHQL_PATH=/graphql + +# login expire time +JWT_EXPIRES_IN=10m # Federation -FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 # if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen # on an hash created from this topic # FEDERATION_DHT_TOPIC=GRADIDO_HUB # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f -FEDERATION_COMMUNITY_URL=http://stage1.gradido.net # the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010 FEDERATION_COMMUNITY_API_PORT=5000 -FEDERATION_CONFIG_VERSION=v1.2023-01-09 # comma separated list of api-versions, which cause starting several federation modules FEDERATION_COMMUNITY_APIS=1_0,1_1 -# database -DATABASE_CONFIG_VERSION=v1.2022-03-18 +# externe gradido services (more added in future) +GDT_API_URL=https://gdt.gradido.net -# frontend -FRONTEND_CONFIG_VERSION=v4.2022-12-20 +# used for combining a newsletter on klicktipp with this gradido community +# if used, user will be subscribed on register and can unsubscribe in his account +KLICKTIPP=false +KLICKTIPP_USER= +KLICKTIPP_PASSWORD= +KLICKTIPP_APIKEY_DE= +KLICKTIPP_APIKEY_EN= -GRAPHQL_URI=https://stage1.gradido.net/graphql -ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} - -DEFAULT_PUBLISHER_ID=2896 - -META_URL=http://localhost +# Meta data in frontend pages, important when shared via facebook or twitter or for search engines META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" META_TITLE_EN="Gradido - Your gratitude account" META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle." @@ -90,8 +86,11 @@ META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natü META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" -# admin -ADMIN_CONFIG_VERSION=v1.2022-03-18 +# update page shown while updating gradido +# page will be fed with status changes +NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page -WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token} -WALLET_URL=https://stage1.gradido.net/login +# LEGACY +NGINX_REWRITE_LEGACY_URLS=false +DEFAULT_PUBLISHER_ID=2896 +WEBHOOK_ELOPAGE_SECRET=secret \ No newline at end of file diff --git a/deployment/bare_metal/doc/server.drawio b/deployment/bare_metal/doc/server.drawio new file mode 100644 index 000000000..e65220821 --- /dev/null +++ b/deployment/bare_metal/doc/server.drawio @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template deleted file mode 100644 index a99327745..000000000 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ /dev/null @@ -1,128 +0,0 @@ -server { - if ($host = $NGINX_SERVER_NAME) { - return 301 https://$host$request_uri; - } - - server_name $NGINX_SERVER_NAME; - listen 80; - listen [::]:80; - return 404; -} - -server { - server_name $NGINX_SERVER_NAME; - - listen [::]:443 ssl ipv6only=on; - listen 443 ssl; - ssl_certificate $NGINX_SSL_CERTIFICATE; - ssl_certificate_key $NGINX_SSL_CERTIFICATE_KEY; - include $NGINX_SSL_INCLUDE; - ssl_dhparam $NGINX_SSL_DHPARAM; - - include /etc/nginx/common/protect.conf; - include /etc/nginx/common/protect_add_header.conf; - - #gzip_static on; - gzip on; - gzip_proxied any; - gzip_types - text/css - text/javascript - text/xml - text/plain - application/javascript - application/x-javascript - application/json; - - # Legacy URLS - set $REWRITE_LEGACY_URLS "$NGINX_REWRITE_LEGACY_URLS"; - if ($REWRITE_LEGACY_URLS = 'true') { - rewrite ^/vue/?(.*)$ /$1 permanent; - } - - # Frontend (default) - location / { - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - - proxy_pass http://127.0.0.1:3000; - proxy_redirect off; - - access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn; - } - - # Backend - location /graphql { - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - - proxy_pass http://127.0.0.1:4000; - proxy_redirect off; - - access_log $GRADIDO_LOG_PATH/nginx-access.backend.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn; - } - - # Backend webhooks - location /hook { - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - - proxy_pass http://127.0.0.1:4000/hook; - proxy_redirect off; - - access_log $GRADIDO_LOG_PATH/nginx-access.backend.hook.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.backend.hook.log warn; - } - - # Webhook reverse proxy - location /hooks/ { - proxy_pass http://127.0.0.1:9000/hooks/; - - access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn; - } - - # Admin Frontend - location /admin { - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - - proxy_pass http://127.0.0.1:8080/; - proxy_redirect off; - - access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; - } - - # Federation - $FEDERATION_NGINX_CONF - - # TODO this could be a performance optimization - #location /vue { - # alias /var/www/html/gradido/frontend/build; - # index index.html; - # - # location ~* \.(png)$ { - # expires 39d; - # } - # try_files $uri $uri/ /index.html = 404; - #} -} \ No newline at end of file diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index f6149a818..1b4732d7c 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -1,5 +1,5 @@ server { - server_name $NGINX_SERVER_NAME; + server_name $COMMUNITY_URL; listen 80; listen [::]:80; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template deleted file mode 100644 index ddcb9ffc1..000000000 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ /dev/null @@ -1,37 +0,0 @@ - -server { - if ($host = $NGINX_SERVER_NAME) { - return 301 https://$host$request_uri; - } - - server_name $NGINX_SERVER_NAME; - listen 80; - listen [::]:80; - return 404; -} -server { - server_name $NGINX_SERVER_NAME; - - listen [::]:443 ssl ipv6only=on; - listen 443 ssl; - ssl_certificate $NGINX_SSL_CERTIFICATE; - ssl_certificate_key $NGINX_SSL_CERTIFICATE_KEY; - include $NGINX_SSL_INCLUDE; - ssl_dhparam $NGINX_SSL_DHPARAM; - - include /etc/nginx/common/protect.conf; - include /etc/nginx/common/protect_add_header.conf; - - gzip on; - - root $NGINX_UPDATE_PAGE_ROOT; - index updating.html; - - location / { - try_files /updating.html =404; - } - - access_log $GRADIDO_LOG_PATH/nginx-access.update-page.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.update-page.log warn; -} - diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 5d5744bd6..bc923c6fa 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -100,8 +100,8 @@ export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locat # *** 3rd generate gradido nginx config including federation modules per api-version echo 'Generate new gradido nginx config' >> $UPDATE_HTML -case "$NGINX_SSL" in - true) TEMPLATE_FILE="gradido.conf.ssl.template" ;; +case "$URL_PROTOCOL" in + 'https') TEMPLATE_FILE="gradido.conf.ssl.template" ;; *) TEMPLATE_FILE="gradido.conf.template" ;; esac envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp @@ -112,8 +112,8 @@ rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations # Generate update-page.conf from template echo 'Generate new update-page nginx config' >> $UPDATE_HTML -case "$NGINX_SSL" in - true) TEMPLATE_FILE="update-page.conf.ssl.template" ;; +case "$URL_PROTOCOL" in + 'https') TEMPLATE_FILE="update-page.conf.ssl.template" ;; *) TEMPLATE_FILE="update-page.conf.template" ;; esac envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/update-page.conf diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md new file mode 100644 index 000000000..01df8663d --- /dev/null +++ b/deployment/hetzner_cloud/README.md @@ -0,0 +1,82 @@ +# Setup on Hetzner Cloud Server +Suggested minimal Plan: CX41 +4x vCPU, 16 GB Ram, 160 GB Disk Space, 20.71 € per month (04.01.2024) + +Suggested OS: +Debian 12 + +For Hetzner Cloud Server a cloud config can be attached, which will be run before first start +https://community.hetzner.com/tutorials/basic-cloud-config/de +https://cloudinit.readthedocs.io/en/latest/reference/examples.html +You can use our [cloudConfig.yaml](./cloudConfig.yaml) but you must insert you own ssh public key, +like this: +```yaml +ssh_authorized_keys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAkLGbzbG7KIGfkssKJBkc/0EVAzQ/8vjvVHzNdxhK8J yourname +``` + +## After Setup Cloud Server with cloudConfig.yaml +### setup your domain pointing on server ip address +### login to your new server as root +```bash +ssh -i /path/to/privKey root@gddhost.tld +``` + +### Change default shell + +```bash +chsh -s /bin/bash +chsh -s /bin/bash gradido +``` + +### Set password for user `gradido` + +```bash +$ passwd gradido +# enter new password twice +``` + +### Switch to the new user + +```bash +su gradido +``` + +### Test authentication via SSH + +If you logout from the server you can test authentication: + +```bash +$ ssh -i /path/to/privKey gradido@gddhost.tld +# This should log you in and allow you to use sudo commands, which will require the user's password +``` + +### Disable password root login via ssh + +```bash +sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.org +sudo sed -i -e '/^\(#\|\)PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config +sudo sed -i '$a AllowUsers gradido' /etc/ssh/sshd_config +sudo /etc/init.d/ssh restart +``` + +### Test SSH Access only, no root ssh access + +```bash +$ ssh gradido@gddhost.tld +# Will result in in either a passphrase request for your key or the message 'Permission denied (publickey)' +$ ssh -i /path/to/privKey root@gddhost.tld +# Will result in 'Permission denied (publickey)' +$ ssh -i /path/to/privKey gradido@gddhost.tld +# Will succeed after entering the correct keys passphrase (if any) +``` + +### Install `Gradido` code +```bash +cd ~ +git clone https://github.com/gradido/gradido.git +``` +### Edit Config +```bash +cd ~/gradido/deployment +cp ./bare_metal/.env.dist ./hetzner_cloud/.env \ No newline at end of file diff --git a/deployment/hetzner_cloud/cloudConfig.yaml b/deployment/hetzner_cloud/cloudConfig.yaml new file mode 100644 index 000000000..86e7d5724 --- /dev/null +++ b/deployment/hetzner_cloud/cloudConfig.yaml @@ -0,0 +1,46 @@ +#cloud-config +users: + - name: gradido + groups: users, admin, sudo + sudo: ALL=(ALL) NOPASSWD:/etc/init.d/nginx start,/etc/init.d/nginx stop,/etc/init.d/nginx restart + shell: /bin/bash + ssh_authorized_keys: + - + +packages: + - fail2ban + - ufw + - git + - mariadb-server + - nginx + - curl + - build-essential + - gnupg + - certbot + - python3-certbot-nginx + - logrotate + - automysqlbackup + - expect +package_update: true +package_upgrade: true + +runcmd: +- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local +- systemctl enable fail2ban + +- ufw allow OpenSSH +- ufw allow http +- ufw allow https +- ufw enable + +- sed -i -e '/^\(#\|\)PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)KbdInteractiveAuthentication/s/^.*$/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)ChallengeResponseAuthentication/s/^.*$/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)MaxAuthTries/s/^.*$/MaxAuthTries 3/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)AllowTcpForwarding/s/^.*$/AllowTcpForwarding no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)X11Forwarding/s/^.*$/X11Forwarding no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)AllowAgentForwarding/s/^.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config +- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config +- sed -i '$a AllowUsers gradido root' /etc/ssh/sshd_config + +- reboot \ No newline at end of file diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh new file mode 100644 index 000000000..c51a2e60b --- /dev/null +++ b/deployment/hetzner_cloud/install.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data +timedatectl set-timezone UTC +timedatectl set-ntp on +apt purge ntp +systemctl start systemd-timesyncd + +set -o allexport +SCRIPT_PATH=$(realpath ../bare_metal) +SCRIPT_DIR=$(dirname $SCRIPT_PATH) +PROJECT_ROOT=$SCRIPT_DIR/../.. +set +o allexport + +# Load .env or .env.dist if not present +# NOTE: all config values will be in process.env when starting +# the services and will therefore take precedence over the .env +if [ -f "./.env" ]; then + set -o allexport + source ./.env + set +o allexport +else + set -o allexport + source $SCRIPT_DIR/.env.dist + set +o allexport +fi + +# Configure git +git config pull.ff only + +# Secure mysql https://gist.github.com/Mins/4602864 +SECURE_MYSQL=$(expect -c " + +set timeout 10 +spawn mysql_secure_installation + +expect \"Enter current password for root (enter for none):\" +send \"\r\" + +expect \"Switch to unix_socket authentication:\" +send \"Y\r\" + +expect \"Change the root password?\" +send \"n\r\" + +expect \"Remove anonymous users?\" +send \"y\r\" + +expect \"Disallow root login remotely?\" +send \"y\r\" + +expect \"Remove test database and access to it?\" +send \"y\r\" + +expect \"Reload privilege tables now?\" +send \"y\r\" + +expect eof +") +echo "$SECURE_MYSQL" \ No newline at end of file diff --git a/deployment/hetzner_cloud/mysql_secure.sh b/deployment/hetzner_cloud/mysql_secure.sh new file mode 100644 index 000000000..2f90c4f4e --- /dev/null +++ b/deployment/hetzner_cloud/mysql_secure.sh @@ -0,0 +1,33 @@ +#!/bin/bash + + +#// Not required in actual script +MYSQL_ROOT_PASSWORD=abcd1234 + +SECURE_MYSQL=$(expect -c " + +set timeout 10 +spawn mysql_secure_installation + +expect \"Enter current password for root (enter for none):\" +send \"$MYSQL\r\" + +expect \"Change the root password?\" +send \"n\r\" + +expect \"Remove anonymous users?\" +send \"y\r\" + +expect \"Disallow root login remotely?\" +send \"y\r\" + +expect \"Remove test database and access to it?\" +send \"y\r\" + +expect \"Reload privilege tables now?\" +send \"y\r\" + +expect eof +") + +echo "$SECURE_MYSQL" diff --git a/nginx/gradido.conf b/nginx/gradido.conf index 403a2766b..2279d1e4f 100644 --- a/nginx/gradido.conf +++ b/nginx/gradido.conf @@ -1,5 +1,5 @@ server { - server_name $NGINX_SERVER_NAME; + server_name _; listen 80; listen [::]:80; From 1258d43d3861af0bdc2af9886abfff4e7f8dd8cb Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 4 Jan 2024 19:18:28 +0100 Subject: [PATCH 02/85] update admin with new url config approach --- README.md | 2 +- admin/.env.dist | 8 +++++--- admin/.env.template | 9 +++++---- admin/src/config/index.js | 16 ++++++++++++---- admin/src/plugins/apolloProvider.js | 2 +- deployment/bare_metal/.env.dist | 6 +++--- .../nginx/sites-available/gradido.conf.template | 2 +- .../sites-available/update-page.conf.template | 2 +- 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 87b4f44e5..91ac65dab 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Each component (frontend, admin, backend and database) has its own `.env` file. Each component has a `.env.dist` file. This file contains all environment variables used by the component and can be used as pattern. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. -Each component has a `.env.template` file. These files are very important on deploy. +Each component has a `.env.template` file. These files are very important on deploy. They use COMMUNITY_HOST instead of different urls for different modules because in deploy using nginx is expected for routing incoming request to the correct module There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating an `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`). diff --git a/admin/.env.dist b/admin/.env.dist index 66c84dda8..d92f3d9bc 100644 --- a/admin/.env.dist +++ b/admin/.env.dist @@ -1,4 +1,6 @@ -GRAPHQL_URI=http://localhost:4000/graphql -WALLET_AUTH_URL=http://localhost/authenticate?token={token} -WALLET_URL=http://localhost/login +GRAPHQL_URL=http://localhost:4000 +GRAPHQL_PATH=/graphql +WALLET_URL=http://localhost +WALLET_AUTH_PATH=/authenticate?token={token} +WALLET_LOGIN_PATH=/login DEBUG_DISABLE_AUTH=false \ No newline at end of file diff --git a/admin/.env.template b/admin/.env.template index 488c9aba4..636b15593 100644 --- a/admin/.env.template +++ b/admin/.env.template @@ -1,6 +1,7 @@ CONFIG_VERSION=$ADMIN_CONFIG_VERSION -GRAPHQL_URI=$GRAPHQL_URI -WALLET_AUTH_URL=$WALLET_AUTH_URL -WALLET_URL=$WALLET_URL -DEBUG_DISABLE_AUTH=false \ No newline at end of file +COMMUNITY_HOST=$COMMUNITY_HOST +WALLET_AUTH_PATH=$WALLET_AUTH_PATH +WALLET_LOGIN_PATH=$WALLET_LOGIN_PATH +GRAPHQL_PATH=$GRAPHQL_PATH +DEBUG_DISABLE_AUTH=false diff --git a/admin/src/config/index.js b/admin/src/config/index.js index fe373386d..10c75579a 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -7,7 +7,7 @@ const pkg = require('../../package') const constants = { CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v1.2022-03-18', + EXPECTED: 'v2.2024-01-04', CURRENT: '', }, } @@ -26,10 +26,18 @@ const environment = { PRODUCTION: process.env.NODE_ENV === 'production' || false, } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST || undefined +const URL_PROTOCOL = process.env.URL_PROTOCOL || 'http' +const COMMUNITY_URL = + COMMUNITY_HOST && URL_PROTOCOL ? URL_PROTOCOL + '://' + COMMUNITY_HOST : undefined +const WALLET_URL = process.env.WALLET_URL || COMMUNITY_URL || 'http://localhost' + const endpoints = { - GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', - WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/authenticate?token={token}', - WALLET_URL: process.env.WALLET_URL || 'http://localhost/login', + GRAPHQL_URL: + (process.env.GRAPHQL_URL || COMMUNITY_URL || 'http://localhost:4000') + + process.env.GRAPHQL_PATH || '/graphql', + WALLET_AUTH_URL: WALLET_URL + (process.env.WALLET_AUTH_PATH || '/authenticate?token={token}'), + WALLET_LOGIN_URL: WALLET_URL + (process.env.WALLET_LOGIN_PATH || '/login'), } const debug = { diff --git a/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js index 8b02013f4..122857031 100644 --- a/admin/src/plugins/apolloProvider.js +++ b/admin/src/plugins/apolloProvider.js @@ -16,7 +16,7 @@ const authLink = new ApolloLink((operation, forward) => { return forward(operation).map((response) => { if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { store.dispatch('logout', null) - window.location.assign(CONFIG.WALLET_URL) + window.location.assign(CONFIG.WALLET_LOGIN_URL) return response } const newToken = operation.getContext().response.headers.get('token') diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 9abc739fb..796bf4d46 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -1,7 +1,7 @@ # Need to adjust! COMMUNITY_NAME="Your community name" COMMUNITY_DESCRIPTION="Short Description from your Community." -COMMUNITY_URL=gddhost.tld +COMMUNITY_HOST=gddhost.tld COMMUNITY_SUPPORT_MAIL=support@supportmail.com # Need to adjust by updates @@ -9,7 +9,7 @@ COMMUNITY_SUPPORT_MAIL=support@supportmail.com DATABASE_CONFIG_VERSION=v1.2022-03-18 BACKEND_CONFIG_VERSION=v17.2023-07-03 FRONTEND_CONFIG_VERSION=v4.2022-12-20 -ADMIN_CONFIG_VERSION=v1.2022-03-18 +ADMIN_CONFIG_VERSION=v2.2024-01-04 FEDERATION_CONFIG_VERSION=v1.2023-01-09 FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 @@ -40,10 +40,10 @@ WEBHOOK_GITHUB_BRANCH=master # frontend and admin paths, usually don't need changes # used in nginx config and for links in emails -WALLET_PATH=/login COMMUNITY_REGISTER_PATH=/register COMMUNITY_REDEEM_PATH=/redeem/{code} COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code} +WALLET_LOGIN_PATH=/login WALLET_AUTH_PATH=/authenticate?token={token} EMAIL_LINK_VERIFICATION=/checkEmail/{optin}{code} EMAIL_LINK_SETPASSWORD=/reset-password/{optin} diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index 1b4732d7c..6b885a26a 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -1,5 +1,5 @@ server { - server_name $COMMUNITY_URL; + server_name $COMMUNITY_HOST; listen 80; listen [::]:80; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.template index c26a705ce..e6cb51c7c 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.template @@ -1,6 +1,6 @@ server { - server_name _; + server_name $COMMUNITY_HOST; listen 80; listen [::]:80; From abda419a284b30edf34167bf2a995087fddbbb77 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 4 Jan 2024 19:32:56 +0100 Subject: [PATCH 03/85] remove unneccessary file --- deployment/hetzner_cloud/mysql_secure.sh | 33 ------------------------ 1 file changed, 33 deletions(-) delete mode 100644 deployment/hetzner_cloud/mysql_secure.sh diff --git a/deployment/hetzner_cloud/mysql_secure.sh b/deployment/hetzner_cloud/mysql_secure.sh deleted file mode 100644 index 2f90c4f4e..000000000 --- a/deployment/hetzner_cloud/mysql_secure.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - - -#// Not required in actual script -MYSQL_ROOT_PASSWORD=abcd1234 - -SECURE_MYSQL=$(expect -c " - -set timeout 10 -spawn mysql_secure_installation - -expect \"Enter current password for root (enter for none):\" -send \"$MYSQL\r\" - -expect \"Change the root password?\" -send \"n\r\" - -expect \"Remove anonymous users?\" -send \"y\r\" - -expect \"Disallow root login remotely?\" -send \"y\r\" - -expect \"Remove test database and access to it?\" -send \"y\r\" - -expect \"Reload privilege tables now?\" -send \"y\r\" - -expect eof -") - -echo "$SECURE_MYSQL" From 6cf488630cc113001624a79e412f20dab5f848f8 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 12:22:20 +0100 Subject: [PATCH 04/85] reduce urls, replace || with ?? https://mariusschulz.com/blog/nullish-coalescing-the-operator-in-typescript --- admin/.env.template | 1 + admin/src/components/NavBar.vue | 4 +-- admin/src/config/index.js | 28 ++++++++--------- backend/.env.dist | 14 ++++----- backend/.env.template | 11 ++++--- backend/src/config/index.ts | 37 ++++++++++++---------- deployment/bare_metal/.env.dist | 12 ++++---- dht-node/.env.template | 3 +- dht-node/src/config/index.ts | 32 ++++++++++--------- dlt-connector/src/config/index.ts | 8 ++--- dlt-database/src/config/index.ts | 12 ++++---- federation/.env.template | 3 +- federation/src/config/index.ts | 28 +++++++++-------- frontend/.env.dist | 6 ++-- frontend/.env.template | 9 +++--- frontend/src/config/index.js | 51 +++++++++++++++++-------------- 16 files changed, 141 insertions(+), 118 deletions(-) diff --git a/admin/.env.template b/admin/.env.template index 636b15593..11e849271 100644 --- a/admin/.env.template +++ b/admin/.env.template @@ -1,6 +1,7 @@ CONFIG_VERSION=$ADMIN_CONFIG_VERSION COMMUNITY_HOST=$COMMUNITY_HOST +URL_PROTOCOL=$URL_PROTOCOL WALLET_AUTH_PATH=$WALLET_AUTH_PATH WALLET_LOGIN_PATH=$WALLET_LOGIN_PATH GRAPHQL_PATH=$GRAPHQL_PATH diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 2efeda048..4191290f3 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -38,8 +38,8 @@ export default { name: 'navbar', methods: { async logout() { - window.location.assign(CONFIG.WALLET_URL) - // window.location = CONFIG.WALLET_URL + window.location.assign(CONFIG.WALLET_LOGIN_URL) + // window.location = CONFIG.WALLET_LOGIN_URL this.$store.dispatch('logout') await this.$apollo.mutate({ mutation: logout, diff --git a/admin/src/config/index.js b/admin/src/config/index.js index 10c75579a..708815398 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -14,38 +14,38 @@ const constants = { const version = { APP_VERSION: pkg.version, - BUILD_COMMIT: process.env.BUILD_COMMIT || null, + BUILD_COMMIT: process.env.BUILD_COMMIT ?? null, // self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code - BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').slice(0, 7), - PORT: process.env.PORT || 8080, + BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7), + PORT: process.env.PORT ?? 8080, } const environment = { NODE_ENV: process.env.NODE_ENV, - DEBUG: process.env.NODE_ENV !== 'production' || false, - PRODUCTION: process.env.NODE_ENV === 'production' || false, + DEBUG: process.env.NODE_ENV !== 'production' ?? false, + PRODUCTION: process.env.NODE_ENV === 'production' ?? false, } -const COMMUNITY_HOST = process.env.COMMUNITY_HOST || undefined -const URL_PROTOCOL = process.env.URL_PROTOCOL || 'http' +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? undefined +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' const COMMUNITY_URL = COMMUNITY_HOST && URL_PROTOCOL ? URL_PROTOCOL + '://' + COMMUNITY_HOST : undefined -const WALLET_URL = process.env.WALLET_URL || COMMUNITY_URL || 'http://localhost' +const WALLET_URL = process.env.WALLET_URL ?? COMMUNITY_URL ?? 'http://localhost' const endpoints = { GRAPHQL_URL: - (process.env.GRAPHQL_URL || COMMUNITY_URL || 'http://localhost:4000') + - process.env.GRAPHQL_PATH || '/graphql', - WALLET_AUTH_URL: WALLET_URL + (process.env.WALLET_AUTH_PATH || '/authenticate?token={token}'), - WALLET_LOGIN_URL: WALLET_URL + (process.env.WALLET_LOGIN_PATH || '/login'), + (process.env.GRAPHQL_URL ?? COMMUNITY_URL ?? 'http://localhost:4000') + + process.env.GRAPHQL_PATH ?? '/graphql', + WALLET_AUTH_URL: WALLET_URL + (process.env.WALLET_AUTH_PATH ?? '/authenticate?token={token}'), + WALLET_LOGIN_URL: WALLET_URL + (process.env.WALLET_LOGIN_PATH ?? '/login'), } const debug = { - DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' || false, + DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' ?? false, } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, diff --git a/backend/.env.dist b/backend/.env.dist index 9844d8c4a..96afd1ab5 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -28,9 +28,9 @@ DLT_CONNECTOR_URL=http://localhost:6010 # Community COMMUNITY_NAME=Gradido Entwicklung COMMUNITY_URL=http://localhost/ -COMMUNITY_REGISTER_URL=http://localhost/register -COMMUNITY_REDEEM_URL=http://localhost/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code} +COMMUNITY_REGISTER_PATH=/register +COMMUNITY_REDEEM_PATH=/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code} COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. COMMUNITY_SUPPORT_MAIL=support@supportmail.com @@ -47,10 +47,10 @@ EMAIL_SENDER=info@gradido.net EMAIL_PASSWORD=xxx EMAIL_SMTP_URL=gmail.com EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password -EMAIL_LINK_OVERVIEW=http://localhost/overview +EMAIL_LINK_VERIFICATION_PATH=/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD_PATH=/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD_PATH=/forgot-password +EMAIL_LINK_OVERVIEW_PATH=/overview EMAIL_CODE_VALID_TIME=1440 EMAIL_CODE_REQUEST_TIME=10 diff --git a/backend/.env.template b/backend/.env.template index e79122368..9133428ab 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -25,14 +25,15 @@ KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN # DltConnector DLT_CONNECTOR=$DLT_CONNECTOR -DLT_CONNECTOR_URL=$DLT_CONNECTOR_URL +DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT # Community +COMMUNITY_HOST=$COMMUNITY_HOST +URL_PROTOCOL=$URL_PROTOCOL COMMUNITY_NAME=$COMMUNITY_NAME -COMMUNITY_URL=$COMMUNITY_URL -COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL -COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL -COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL +COMMUNITY_REGISTER_PATH=$COMMUNITY_REGISTER_PATH +COMMUNITY_REDEEM_PATH=$COMMUNITY_REDEEM_PATH +COMMUNITY_REDEEM_CONTRIBUTION_PATH=$COMMUNITY_REDEEM_CONTRIBUTION_PATH COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION COMMUNITY_SUPPORT_MAIL=$COMMUNITY_SUPPORT_MAIL diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 6f03d21b9..cbb9eabf9 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -19,7 +19,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v20.2023-09-19', + EXPECTED: 'v21.2024-01-06', CURRENT: '', }, } @@ -51,18 +51,23 @@ const klicktipp = { KLICKTIPP_APIKEY_EN: process.env.KLICKTIPP_APIKEY_EN ?? 'SomeFakeKeyEN', } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost' +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' +const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}` +const DLT_CONNECTOR_PORT = process.env.DLT_CONNECTOR_PORT ?? 6010 + const dltConnector = { DLT_CONNECTOR: process.env.DLT_CONNECTOR === 'true' || false, - DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? 'http://localhost:6010', + DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `${COMMUNITY_URL}:${DLT_CONNECTOR_PORT}`, } const community = { COMMUNITY_NAME: process.env.COMMUNITY_NAME ?? 'Gradido Entwicklung', - COMMUNITY_URL: process.env.COMMUNITY_URL ?? 'http://localhost/', - COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL ?? 'http://localhost/register', - COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL ?? 'http://localhost/redeem/{code}', + COMMUNITY_URL, + COMMUNITY_REGISTER_URL: COMMUNITY_URL + (process.env.COMMUNITY_REGISTER_PATH ?? '/register'), + COMMUNITY_REDEEM_URL: COMMUNITY_URL + (process.env.COMMUNITY_REDEEM_PATH ?? '/redeem/{code}'), COMMUNITY_REDEEM_CONTRIBUTION_URL: - process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL ?? 'http://localhost/redeem/CL-{code}', + COMMUNITY_URL + (process.env.COMMUNITY_REDEEM_CONTRIBUTION_PATH ?? '/redeem/CL-{code}'), COMMUNITY_DESCRIPTION: process.env.COMMUNITY_DESCRIPTION ?? 'Die lokale Entwicklungsumgebung von Gradido.', COMMUNITY_SUPPORT_MAIL: process.env.COMMUNITY_SUPPORT_MAIL ?? 'support@supportmail.com', @@ -74,8 +79,8 @@ const loginServer = { } const email = { - EMAIL: process.env.EMAIL === 'true' || false, - EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true' || false, + EMAIL: process.env.EMAIL === 'true' ?? false, + EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true' ?? false, EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER ?? 'stage1@gradido.net', EMAIL_USERNAME: process.env.EMAIL_USERNAME ?? '', EMAIL_SENDER: process.env.EMAIL_SENDER ?? 'info@gradido.net', @@ -85,19 +90,19 @@ const email = { // eslint-disable-next-line no-unneeded-ternary EMAIL_TLS: process.env.EMAIL_TLS === 'false' ? false : true, EMAIL_LINK_VERIFICATION: - process.env.EMAIL_LINK_VERIFICATION ?? 'http://localhost/checkEmail/{optin}{code}', + COMMUNITY_URL + (process.env.EMAIL_LINK_VERIFICATION_PATH ?? '/checkEmail/{optin}{code}'), EMAIL_LINK_SETPASSWORD: - process.env.EMAIL_LINK_SETPASSWORD ?? 'http://localhost/reset-password/{optin}', + COMMUNITY_URL + (process.env.EMAIL_LINK_SETPASSWORD_PATH ?? '/reset-password/{optin}'), EMAIL_LINK_FORGOTPASSWORD: - process.env.EMAIL_LINK_FORGOTPASSWORD ?? 'http://localhost/forgot-password', - EMAIL_LINK_OVERVIEW: process.env.EMAIL_LINK_OVERVIEW ?? 'http://localhost/overview', + COMMUNITY_URL + (process.env.EMAIL_LINK_FORGOTPASSWORD_PATH ?? '/forgot-password'), + EMAIL_LINK_OVERVIEW: COMMUNITY_URL + (process.env.EMAIL_LINK_OVERVIEW_PATH ?? '/overview'), // time in minutes a optin code is valid EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME - ? parseInt(process.env.EMAIL_CODE_VALID_TIME) || 1440 + ? parseInt(process.env.EMAIL_CODE_VALID_TIME) ?? 1440 : 1440, // time in minutes that must pass to request a new optin code EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME - ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) || 10 + ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) ?? 10 : 10, } @@ -124,9 +129,9 @@ if ( const federation = { FEDERATION_BACKEND_SEND_ON_API: process.env.FEDERATION_BACKEND_SEND_ON_API ?? '1_0', FEDERATION_VALIDATE_COMMUNITY_TIMER: - Number(process.env.FEDERATION_VALIDATE_COMMUNITY_TIMER) || 60000, + Number(process.env.FEDERATION_VALIDATE_COMMUNITY_TIMER) ?? 60000, FEDERATION_XCOM_SENDCOINS_ENABLED: - process.env.FEDERATION_XCOM_SENDCOINS_ENABLED === 'true' || false, + process.env.FEDERATION_XCOM_SENDCOINS_ENABLED === 'true' ?? false, // default value for community-uuid is equal uuid of stage-3 FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID: process.env.FEDERATION_XCOM_RECEIVER_COMMUNITY_UUID ?? '56a55482-909e-46a4-bfa2-cd025e894ebc', diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 796bf4d46..973a9e8a6 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -7,8 +7,8 @@ COMMUNITY_SUPPORT_MAIL=support@supportmail.com # Need to adjust by updates # config versions DATABASE_CONFIG_VERSION=v1.2022-03-18 -BACKEND_CONFIG_VERSION=v17.2023-07-03 -FRONTEND_CONFIG_VERSION=v4.2022-12-20 +BACKEND_CONFIG_VERSION=v21.2024-01-06 +FRONTEND_CONFIG_VERSION=v5.2024-01-08 ADMIN_CONFIG_VERSION=v2.2024-01-04 FEDERATION_CONFIG_VERSION=v1.2023-01-09 FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 @@ -45,10 +45,10 @@ COMMUNITY_REDEEM_PATH=/redeem/{code} COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code} WALLET_LOGIN_PATH=/login WALLET_AUTH_PATH=/authenticate?token={token} -EMAIL_LINK_VERIFICATION=/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=/forgot-password -EMAIL_LINK_OVERVIEW=/overview +EMAIL_LINK_VERIFICATION_PATH=/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD_PATH=/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD_PATH=/forgot-password +EMAIL_LINK_OVERVIEW_PATH=/overview ADMIN_AUTH_PATH=/admin/authenticate?token={token} GRAPHQL_PATH=/graphql diff --git a/dht-node/.env.template b/dht-node/.env.template index 1278f61be..c342247e5 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -19,5 +19,6 @@ FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # on an hash created from this topic FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED -FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL +COMMUNITY_HOST=$COMMUNITY_HOST +URL_PROTOCOL=$URL_PROTOCOL FEDERATION_COMMUNITY_API_PORT=$FEDERATION_COMMUNITY_API_PORT diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 2548166f4..90f99fcf5 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -7,7 +7,7 @@ const constants = { DB_VERSION: '0078-move_resubmission_date', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', + LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', EXPECTED: 'v3.2023-04-26', @@ -16,34 +16,38 @@ const constants = { } const server = { - PRODUCTION: process.env.NODE_ENV === 'production' || false, + PRODUCTION: process.env.NODE_ENV === 'production' ?? false, } const database = { - DB_HOST: process.env.DB_HOST || 'localhost', + DB_HOST: process.env.DB_HOST ?? 'localhost', DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER || 'root', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', + DB_USER: process.env.DB_USER ?? 'root', + DB_PASSWORD: process.env.DB_PASSWORD ?? '', + DB_DATABASE: process.env.DB_DATABASE ?? 'gradido_community', TYPEORM_LOGGING_RELATIVE_PATH: - process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.dht-node.log', + process.env.TYPEORM_LOGGING_RELATIVE_PATH ?? 'typeorm.dht-node.log', } const community = { - COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', + COMMUNITY_NAME: process.env.COMMUNITY_NAME ?? 'Gradido Entwicklung', COMMUNITY_DESCRIPTION: - process.env.COMMUNITY_DESCRIPTION || 'Gradido-Community einer lokalen Entwicklungsumgebung.', + process.env.COMMUNITY_DESCRIPTION ?? 'Gradido-Community einer lokalen Entwicklungsumgebung.', } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost' +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' +const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}` + const federation = { - FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || 'GRADIDO_HUB', - FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null, - FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || 'http://localhost', - FEDERATION_COMMUNITY_API_PORT: process.env.FEDERATION_COMMUNITY_API_PORT || '5000', + FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC ?? 'GRADIDO_HUB', + FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED ?? null, + FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL ?? COMMUNITY_URL, + FEDERATION_COMMUNITY_API_PORT: process.env.FEDERATION_COMMUNITY_API_PORT ?? '5000', } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index fc8c780b8..37332a4b2 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -6,7 +6,7 @@ const constants = { LOG4JS_CONFIG: 'log4js-config.json', DB_VERSION: '0002-refactor_add_community', // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', + LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', EXPECTED: 'v4.2023-09-12', @@ -15,7 +15,7 @@ const constants = { } const server = { - PRODUCTION: process.env.NODE_ENV === 'production' || false, + PRODUCTION: process.env.NODE_ENV === 'production' ?? false, } const database = { @@ -35,11 +35,11 @@ const iota = { } const dltConnector = { - DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT || 6010, + DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT ?? 6010, } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, diff --git a/dlt-database/src/config/index.ts b/dlt-database/src/config/index.ts index 20208befc..46a1e580c 100644 --- a/dlt-database/src/config/index.ts +++ b/dlt-database/src/config/index.ts @@ -13,19 +13,19 @@ const constants = { } const database = { - DB_HOST: process.env.DB_HOST || 'localhost', + DB_HOST: process.env.DB_HOST ?? 'localhost', DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER || 'root', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || 'gradido_dlt', + DB_USER: process.env.DB_USER ?? 'root', + DB_PASSWORD: process.env.DB_PASSWORD ?? '', + DB_DATABASE: process.env.DB_DATABASE ?? 'gradido_dlt', } const migrations = { - MIGRATIONS_TABLE: process.env.MIGRATIONS_TABLE || 'migrations', + MIGRATIONS_TABLE: process.env.MIGRATIONS_TABLE ?? 'migrations', } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, diff --git a/federation/.env.template b/federation/.env.template index e6ac8ad7d..91fb1c692 100644 --- a/federation/.env.template +++ b/federation/.env.template @@ -13,7 +13,8 @@ DB_PASSWORD=$DB_PASSWORD DB_DATABASE=gradido_community # Federation -FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL +COMMUNITY_HOST=$COMMUNITY_HOST +URL_PROTOCOL=$URL_PROTOCOL FEDERATION_CONFIG_VERSION=$FEDERATION_CONFIG_VERSION # comma separated list of api-versions, which cause starting several federation modules FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS \ No newline at end of file diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 036ce67ee..a538080cb 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -14,7 +14,7 @@ const constants = { DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', + LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', EXPECTED: 'v2.2023-08-24', @@ -25,21 +25,21 @@ const constants = { const server = { // JWT_SECRET: process.env.JWT_SECRET || 'secret123', // JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', - GRAPHIQL: process.env.GRAPHIQL === 'true' || false, + GRAPHIQL: process.env.GRAPHIQL === 'true' ?? false, // GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', - PRODUCTION: process.env.NODE_ENV === 'production' || false, + PRODUCTION: process.env.NODE_ENV === 'production' ?? false, } const database = { - DB_HOST: process.env.DB_HOST || 'localhost', + DB_HOST: process.env.DB_HOST ?? 'localhost', DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER || 'root', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', - TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', + DB_USER: process.env.DB_USER ?? 'root', + DB_PASSWORD: process.env.DB_PASSWORD ?? '', + DB_DATABASE: process.env.DB_DATABASE ?? 'gradido_community', + TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH ?? 'typeorm.backend.log', } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, @@ -50,10 +50,14 @@ if ( ) } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost' +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' +const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}` + const federation = { - FEDERATION_API: process.env.FEDERATION_API || '1_0', - FEDERATION_PORT: process.env.FEDERATION_PORT || 5010, - FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || null, + FEDERATION_API: process.env.FEDERATION_API ?? '1_0', + FEDERATION_PORT: process.env.FEDERATION_PORT ?? 5010, + FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL ?? COMMUNITY_URL, FEDERATION_TRADING_LEVEL: { RECEIVER_COMMUNITY_URL: 'https://stage3.gradido.net/api/', SEND_COINS: true, diff --git a/frontend/.env.dist b/frontend/.env.dist index 427d43359..f7e7edcd6 100644 --- a/frontend/.env.dist +++ b/frontend/.env.dist @@ -2,13 +2,13 @@ DEFAULT_PUBLISHER_ID=2896 # Endpoints -GRAPHQL_URI=http://localhost/graphql -ADMIN_AUTH_URL=http://localhost/admin/authenticate?token={token} +GRAPHQL_PATH=/graphql +ADMIN_AUTH_PATH=/admin/authenticate?token={token} # Community COMMUNITY_NAME=Gradido Entwicklung COMMUNITY_URL=http://localhost/ -COMMUNITY_REGISTER_URL=http://localhost/register +COMMUNITY_REGISTER_PATH=/register COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. COMMUNITY_SUPPORT_MAIL=support@supportmail.com diff --git a/frontend/.env.template b/frontend/.env.template index 59e34eb80..e5662140c 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -4,13 +4,14 @@ CONFIG_VERSION=$FRONTEND_CONFIG_VERSION DEFAULT_PUBLISHER_ID=$DEFAULT_PUBLISHER_ID # Endpoints -GRAPHQL_URI=$GRAPHQL_URI -ADMIN_AUTH_URL=$ADMIN_AUTH_URL +GRAPHQL_PATH=$GRAPHQL_PATH +ADMIN_AUTH_PATH=$ADMIN_AUTH_PATH # Community COMMUNITY_NAME=$COMMUNITY_NAME -COMMUNITY_URL=$COMMUNITY_URL -COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL +COMMUNITY_HOST=$COMMUNITY_HOST +URL_PROTOCOL=$URL_PROTOCOL +COMMUNITY_REGISTER_PATH=$COMMUNITY_REGISTER_PATH COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION COMMUNITY_SUPPORT_MAIL=$COMMUNITY_SUPPORT_MAIL diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index b90376672..dd2e85dac 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -8,61 +8,66 @@ const constants = { DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v4.2022-12-20', + EXPECTED: 'v5.2024-01-08', CURRENT: '', }, } const version = { APP_VERSION: pkg.version, - BUILD_COMMIT: process.env.BUILD_COMMIT || null, + BUILD_COMMIT: process.env.BUILD_COMMIT ?? null, // self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code - BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').slice(0, 7), + BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7), } const environment = { NODE_ENV: process.env.NODE_ENV, - DEBUG: process.env.NODE_ENV !== 'production' || false, - PRODUCTION: process.env.NODE_ENV === 'production' || false, - DEFAULT_PUBLISHER_ID: process.env.DEFAULT_PUBLISHER_ID || 2896, - PORT: process.env.PORT || 3000, + DEBUG: process.env.NODE_ENV !== 'production' ?? false, + PRODUCTION: process.env.NODE_ENV === 'production' ?? false, + DEFAULT_PUBLISHER_ID: process.env.DEFAULT_PUBLISHER_ID ?? 2896, + PORT: process.env.PORT ?? 3000, } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost' +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' +const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}` + const endpoints = { - GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost/graphql', - ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token={token}', + GRAPHQL_URI: COMMUNITY_URL + (process.env.GRAPHQL_PATH ?? '/graphql'), + ADMIN_AUTH_URL: + COMMUNITY_URL + (process.env.ADMIN_AUTH_PATH ?? '/admin/authenticate?token={token}'), } const community = { - COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', - COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', - COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', + COMMUNITY_NAME: process.env.COMMUNITY_NAME ?? 'Gradido Entwicklung', + COMMUNITY_URL: COMMUNITY_URL, + COMMUNITY_REGISTER_URL: COMMUNITY_URL + (process.env.COMMUNITY_REGISTER_PATH ?? '/register'), COMMUNITY_DESCRIPTION: - process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', - COMMUNITY_SUPPORT_MAIL: process.env.COMMUNITY_SUPPORT_MAIL || 'support@supportmail.com', + process.env.COMMUNITY_DESCRIPTION ?? 'Die lokale Entwicklungsumgebung von Gradido.', + COMMUNITY_SUPPORT_MAIL: process.env.COMMUNITY_SUPPORT_MAIL ?? 'support@supportmail.com', } const meta = { - META_URL: process.env.META_URL || 'http://localhost', - META_TITLE_DE: process.env.META_TITLE_DE || 'Gradido – Dein Dankbarkeitskonto', - META_TITLE_EN: process.env.META_TITLE_EN || 'Gradido - Your gratitude account', + META_URL: process.env.META_URL ?? 'http://localhost', + META_TITLE_DE: process.env.META_TITLE_DE ?? 'Gradido – Dein Dankbarkeitskonto', + META_TITLE_EN: process.env.META_TITLE_EN ?? 'Gradido - Your gratitude account', META_DESCRIPTION_DE: - process.env.META_DESCRIPTION_DE || + process.env.META_DESCRIPTION_DE ?? 'Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle.', META_DESCRIPTION_EN: - process.env.META_DESCRIPTION_EN || + process.env.META_DESCRIPTION_EN ?? 'Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all.', META_KEYWORDS_DE: - process.env.META_KEYWORDS_DE || + process.env.META_KEYWORDS_DE ?? 'Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem', META_KEYWORDS_EN: - process.env.META_KEYWORDS_EN || + process.env.META_KEYWORDS_EN ?? 'Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System', - META_AUTHOR: process.env.META_AUTHOR || 'Bernd Hückstädt - Gradido-Akademie', + META_AUTHOR: process.env.META_AUTHOR ?? 'Bernd Hückstädt - Gradido-Akademie', } // Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT if ( ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( constants.CONFIG_VERSION.CURRENT, From 29fc999a8b2ebb1514c8b011ea95ae3e679b9e59 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 12:37:26 +0100 Subject: [PATCH 05/85] bugfix --- .../src/emails/templates/addedContributionMessage/html.pug | 2 +- .../emails/templates/includes/contributionDetailsCTA.pug | 4 ++-- .../src/emails/templates/transactionLinkRedeemed/html.pug | 2 +- backend/src/emails/templates/transactionReceived/html.pug | 2 +- dlt-database/migrations/0001-init_db.ts | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/src/emails/templates/addedContributionMessage/html.pug b/backend/src/emails/templates/addedContributionMessage/html.pug index 7865b2099..ff7c89c30 100644 --- a/backend/src/emails/templates/addedContributionMessage/html.pug +++ b/backend/src/emails/templates/addedContributionMessage/html.pug @@ -9,6 +9,6 @@ block content h2= t('emails.addedContributionMessage.readMessage') div(class="p_content")= t('emails.addedContributionMessage.toSeeAndAnswerMessage') - a.button-3(href=`${communityURL}community/contributions`) #{t('emails.general.toAccount')} + a.button-3(href=`${communityURL}/community/contributions`) #{t('emails.general.toAccount')} include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/includes/contributionDetailsCTA.pug b/backend/src/emails/templates/includes/contributionDetailsCTA.pug index fb2906419..0a3bd395d 100644 --- a/backend/src/emails/templates/includes/contributionDetailsCTA.pug +++ b/backend/src/emails/templates/includes/contributionDetailsCTA.pug @@ -1,7 +1,7 @@ //- h2= t('emails.general.contributionDetails') div(class="p_content")= t('emails.contribution.toSeeContributionsAndMessages') -a.button-3(href=`${communityURL}community/contributions`) #{t('emails.general.toAccount')} +a.button-3(href=`${communityURL}/community/contributions`) #{t('emails.general.toAccount')} div(class="p_content")= t('emails.general.orCopyLink') -a.clink(href=`${communityURL}community/contributions`) #{`${communityURL}community/contributions`} \ No newline at end of file +a.clink(href=`${communityURL}/community/contributions`) #{`${communityURL}/community/contributions`} \ No newline at end of file diff --git a/backend/src/emails/templates/transactionLinkRedeemed/html.pug b/backend/src/emails/templates/transactionLinkRedeemed/html.pug index b24c5da40..281ee9205 100644 --- a/backend/src/emails/templates/transactionLinkRedeemed/html.pug +++ b/backend/src/emails/templates/transactionLinkRedeemed/html.pug @@ -13,6 +13,6 @@ block content br = t('emails.general.detailsYouFindOnLinkToYourAccount') - a.button-3(href=`${communityURL}transactions`) #{t('emails.general.toAccount')} + a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/transactionReceived/html.pug b/backend/src/emails/templates/transactionReceived/html.pug index 93de2c88e..5370ec03e 100644 --- a/backend/src/emails/templates/transactionReceived/html.pug +++ b/backend/src/emails/templates/transactionReceived/html.pug @@ -9,7 +9,7 @@ block content h2= t('emails.general.transactionDetails') div(class="p_content")= t('emails.general.detailsYouFindOnLinkToYourAccount') - a.button-3(href=`${communityURL}transactions`) #{t('emails.general.toAccount')} + a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} include ../includes/doNotReply.pug diff --git a/dlt-database/migrations/0001-init_db.ts b/dlt-database/migrations/0001-init_db.ts index 85fed59e0..8188a889d 100644 --- a/dlt-database/migrations/0001-init_db.ts +++ b/dlt-database/migrations/0001-init_db.ts @@ -23,7 +23,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`confirmed_at\` datetime(3) DEFAULT NULL, PRIMARY KEY (\`id\`), INDEX \`gradido_id\` (\`gradido_id\`), - UNIQUE KEY \`pubkey\` (\`pubkey\`) + UNIQUE KEY \`derive1_pubkey\` (\`derive1_pubkey\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) await queryFn(` @@ -38,7 +38,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`balance\` decimal(40,20) NOT NULL DEFAULT 0, \`balance_date\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (\`id\`), - UNIQUE KEY \`pubkey\` (\`pubkey\`), + UNIQUE KEY \`derive2_pubkey\` (\`derive2_pubkey\`), FOREIGN KEY (\`user_id\`) REFERENCES users(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; `) @@ -56,7 +56,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), \`confirmed_at\` datetime(3) DEFAULT NULL, PRIMARY KEY (\`id\`), - UNIQUE KEY \`pubkey\` (\`pubkey\`), + UNIQUE KEY \`root_pubkey\` (\`root_pubkey\`), FOREIGN KEY (\`gmw_account_id\`) REFERENCES accounts(id), FOREIGN KEY (\`auf_account_id\`) REFERENCES accounts(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) From 464e993da2b96af299063219b65a12d48fa45a54 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 13:13:03 +0100 Subject: [PATCH 06/85] update .env --- deployment/bare_metal/.env.dist | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 973a9e8a6..dd5e75484 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -4,6 +4,17 @@ COMMUNITY_DESCRIPTION="Short Description from your Community." COMMUNITY_HOST=gddhost.tld COMMUNITY_SUPPORT_MAIL=support@supportmail.com +# setup email account for sending gradido system messages to users +EMAIL=true +EMAIL_TEST_MODUS=false +EMAIL_TEST_RECEIVER=test_team@gradido.net +EMAIL_USERNAME=peter@lustig.de +EMAIL_SENDER=peter@lustig.de +EMAIL_PASSWORD=1234 +EMAIL_SMTP_URL=smtp.lustig.de +EMAIL_CODE_VALID_TIME=1440 +EMAIL_CODE_REQUEST_TIME=10 + # Need to adjust by updates # config versions DATABASE_CONFIG_VERSION=v1.2022-03-18 @@ -19,17 +30,6 @@ URL_PROTOCOL=https # only for test server DEPLOY_SEED_DATA=false -# setup email account for sending gradido system messages to users -EMAIL=true -EMAIL_TEST_MODUS=false -EMAIL_TEST_RECEIVER=test_team@gradido.net -EMAIL_USERNAME=peter@lustig.de -EMAIL_SENDER=peter@lustig.de -EMAIL_PASSWORD=1234 -EMAIL_SMTP_URL=smtp.lustig.de -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - # Logging GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log TYPEORM_LOGGING_RELATIVE_PATH=/home/gradido/gradido/deployment/bare_metal/log/typeorm.backend.log From bd59e06d170ea37e293b1d8f48d5353f2a0b3224 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 15:59:55 +0100 Subject: [PATCH 07/85] install.sh can run on command line, certbort used for https, FEDERATION_DHT_SEED generate and loaded in start.sh --- deployment/bare_metal/.env.dist | 2 + deployment/bare_metal/start.sh | 25 ++++++---- deployment/hetzner_cloud/README.md | 31 +++++++++++- deployment/hetzner_cloud/install.sh | 73 ++++++++++++++++++++++++++++- 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index dd5e75484..59cbf042e 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -24,6 +24,8 @@ ADMIN_CONFIG_VERSION=v2.2024-01-04 FEDERATION_CONFIG_VERSION=v1.2023-01-09 FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 +FEDERATION_DHT_TOPIC=GRADIDO_HUB + # Need adjustments for test system URL_PROTOCOL=https # start script diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index bc923c6fa..db67cc0d9 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -14,8 +14,10 @@ set +o allexport # the services and will therefore take precedence over the .env # We have to load the backend .env to get DB_USERNAME, DB_PASSWORD AND JWT_SECRET +# and the dht-node .env to get FEDERATION_DHT_SEED export_var(){ export $1=$(grep -v '^#' $PROJECT_ROOT/backend/.env | grep -e "$1" | sed -e 's/.*=//') + export $1=$(grep -v '^#' $PROJECT_ROOT/dht-node/.env | grep -e "$1" | sed -e 's/.*=//') } if [ -f "$PROJECT_ROOT/backend/.env" ]; then @@ -24,6 +26,10 @@ if [ -f "$PROJECT_ROOT/backend/.env" ]; then export_var 'JWT_SECRET' fi +if [ -f "$PROJECT_ROOT/dht-node/.env" ]; then + export_var 'FEDERATION_DHT_SEED' +fi + # Load .env or .env.dist if not present if [ -f "$SCRIPT_DIR/.env" ]; then set -o allexport @@ -57,6 +63,10 @@ echo 'Configuring nginx to serve the update-page' >> $UPDATE_HTML rm /etc/nginx/sites-enabled/gradido.conf ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/ sudo /etc/init.d/nginx restart +# enable https if env variable has value https +if [ "$URL_PROTOCOL" = "https" ]; then + certbot --nginx --non-interactive +fi # stop all services echo 'Stop and delete all Gradido services' >> $UPDATE_HTML @@ -100,11 +110,7 @@ export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locat # *** 3rd generate gradido nginx config including federation modules per api-version echo 'Generate new gradido nginx config' >> $UPDATE_HTML -case "$URL_PROTOCOL" in - 'https') TEMPLATE_FILE="gradido.conf.ssl.template" ;; - *) TEMPLATE_FILE="gradido.conf.template" ;; -esac -envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp +envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/gradido.conf.template > $NGINX_CONFIG_DIR/gradido.conf.tmp unset FEDERATION_NGINX_CONF envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/gradido.conf.tmp > $NGINX_CONFIG_DIR/gradido.conf rm $NGINX_CONFIG_DIR/gradido.conf.tmp @@ -112,11 +118,7 @@ rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations # Generate update-page.conf from template echo 'Generate new update-page nginx config' >> $UPDATE_HTML -case "$URL_PROTOCOL" in - 'https') TEMPLATE_FILE="update-page.conf.ssl.template" ;; - *) TEMPLATE_FILE="update-page.conf.template" ;; -esac -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/update-page.conf +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/update-page.conf.template > $NGINX_CONFIG_DIR/update-page.conf # Clean tmp folder - remove yarn files find /tmp -name "yarn--*" -exec rm -r {} \; @@ -262,6 +264,9 @@ echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/ rm /etc/nginx/sites-enabled/update-page.conf sudo /etc/init.d/nginx restart +if [ "$URL_PROTOCOL" = "https" ]; then + certbot --nginx --non-interactive +fi # keep the update log cat $UPDATE_HTML >> $GRADIDO_LOG_PATH/update.$TODAY.log diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md index 01df8663d..fbad7ace6 100644 --- a/deployment/hetzner_cloud/README.md +++ b/deployment/hetzner_cloud/README.md @@ -76,7 +76,34 @@ $ ssh -i /path/to/privKey gradido@gddhost.tld cd ~ git clone https://github.com/gradido/gradido.git ``` -### Edit Config + +### Adjust the values in `.env` + +***!!! Attention !!!*** + +*Don't forget this step! +All your following installations in `install.sh` will fail!* + +*Notes:* + +- *`;` cannot be part of any value!* +- *The GitHub secret is created on GitHub in Settings -> Webhooks.* + +#### Create `.env` and set values + ```bash cd ~/gradido/deployment -cp ./bare_metal/.env.dist ./hetzner_cloud/.env \ No newline at end of file +cp ./bare_metal/.env.dist ./hetzner_cloud/.env +cd hetzner_cloud/ +nano .env +# adjust values accordingly +``` + +### Run `install.sh` +***!!! Attention !!!*** +Don't use this script if you have custom config in /etc/nginx/conf.d, because this script +will remove it and ln ../bare_metal/nginx/conf.d + +```bash +sudo chmod +x ./install.sh +sudo ./install.sh \ No newline at end of file diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index c51a2e60b..64f6240ec 100644 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -57,4 +57,75 @@ send \"y\r\" expect eof ") -echo "$SECURE_MYSQL" \ No newline at end of file +echo "$SECURE_MYSQL" + +# Configure nginx +rm /etc/nginx/sites-enabled/default +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/nginx/sites-available/gradido.conf.template > $SCRIPT_DIR/nginx/sites-available/gradido.conf +ln -s $SCRIPT_DIR/nginx/sites-available/gradido.conf /etc/nginx/sites-available +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/nginx/sites-available/update-page.conf.template > $SCRIPT_DIR/nginx/sites-available/update-page.conf +ln -s $SCRIPT_DIR/nginx/sites-available/update-page.conf /etc/nginx/sites-available +ln -s $SCRIPT_DIR/nginx/common /etc/nginx/ +rmdir /etc/nginx/conf.d +ln -s $SCRIPT_DIR/nginx/conf.d /etc/nginx/ + +# setup https with certbot +certbot --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL + +# Install node 16.x +curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - +apt-get install -y nodejs + +# Install yarn +curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +apt-get update +apt-get install -y yarn + +# Install pm2 +yarn global add pm2 +pm2 startup + +# Install logrotate +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/logrotate/gradido.conf.template > $SCRIPT_DIR/logrotate/gradido.conf +cp $SCRIPT_DIR/logrotate/gradido.conf /etc/logrotate.d/gradido.conf +chown root:root /etc/logrotate.d/gradido.conf + +# create db user +export DB_USER=gradido +export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +mysql < $PROJECT_ROOT/database/.env + +# Configure backend +export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env + +# Configure frontend +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env + +# Configure admin +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env + +# Configure dht-node +export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env + +# Configure federation +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env + +# create cronjob to delete yarn output in /tmp +# crontab -e +# hourly job: 0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null +crontab -l | { cat; echo "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null"; } | crontab - +# daily job: 0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null +crontab -l | { cat; echo "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null"; } | crontab - +# Start gradido +# Note: on first startup some errors will occur - nothing serious +$SCRIPT_PATH/start.sh \ No newline at end of file From 3c1449f9d59966a76333c623ba3b520ff957bf11 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 16:12:50 +0100 Subject: [PATCH 08/85] move .env to bare_metal --- deployment/hetzner_cloud/README.md | 7 ++++--- deployment/hetzner_cloud/install.sh | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md index fbad7ace6..9f0bb94e6 100644 --- a/deployment/hetzner_cloud/README.md +++ b/deployment/hetzner_cloud/README.md @@ -92,10 +92,10 @@ All your following installations in `install.sh` will fail!* #### Create `.env` and set values ```bash -cd ~/gradido/deployment -cp ./bare_metal/.env.dist ./hetzner_cloud/.env -cd hetzner_cloud/ +cd ~/gradido/deployment/bare_metal +cp .env.dist .env nano .env + # adjust values accordingly ``` @@ -105,5 +105,6 @@ Don't use this script if you have custom config in /etc/nginx/conf.d, because th will remove it and ln ../bare_metal/nginx/conf.d ```bash +cd ~/gradido/deployment/hetzner_cloud sudo chmod +x ./install.sh sudo ./install.sh \ No newline at end of file diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 64f6240ec..538386bf0 100644 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -17,7 +17,7 @@ set +o allexport # the services and will therefore take precedence over the .env if [ -f "./.env" ]; then set -o allexport - source ./.env + source $SCRIPT_DIR/.env set +o allexport else set -o allexport From 912b2dc679045cb53e5443f84bd6c5f57a3937ff Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 16:18:55 +0100 Subject: [PATCH 09/85] make install.sh executable --- deployment/hetzner_cloud/install.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 deployment/hetzner_cloud/install.sh diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh old mode 100644 new mode 100755 From 646f78dd5df10d115a8341c55c43e5e96d6264ac Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 16:30:24 +0100 Subject: [PATCH 10/85] adjust paths --- deployment/hetzner_cloud/install.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 538386bf0..cdde55080 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -9,7 +9,7 @@ systemctl start systemd-timesyncd set -o allexport SCRIPT_PATH=$(realpath ../bare_metal) SCRIPT_DIR=$(dirname $SCRIPT_PATH) -PROJECT_ROOT=$SCRIPT_DIR/../.. +PROJECT_ROOT=$SCRIPT_DIR/.. set +o allexport # Load .env or .env.dist if not present @@ -17,11 +17,11 @@ set +o allexport # the services and will therefore take precedence over the .env if [ -f "./.env" ]; then set -o allexport - source $SCRIPT_DIR/.env + source $SCRIPT_PATH/.env set +o allexport else set -o allexport - source $SCRIPT_DIR/.env.dist + source $SCRIPT_PATH/.env.dist set +o allexport fi @@ -61,13 +61,13 @@ echo "$SECURE_MYSQL" # Configure nginx rm /etc/nginx/sites-enabled/default -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/nginx/sites-available/gradido.conf.template > $SCRIPT_DIR/nginx/sites-available/gradido.conf +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf ln -s $SCRIPT_DIR/nginx/sites-available/gradido.conf /etc/nginx/sites-available -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/nginx/sites-available/update-page.conf.template > $SCRIPT_DIR/nginx/sites-available/update-page.conf -ln -s $SCRIPT_DIR/nginx/sites-available/update-page.conf /etc/nginx/sites-available -ln -s $SCRIPT_DIR/nginx/common /etc/nginx/ +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf +ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf /etc/nginx/sites-available +ln -s $SCRIPT_PATH/nginx/common /etc/nginx/ rmdir /etc/nginx/conf.d -ln -s $SCRIPT_DIR/nginx/conf.d /etc/nginx/ +ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ # setup https with certbot certbot --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL @@ -87,8 +87,8 @@ yarn global add pm2 pm2 startup # Install logrotate -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_DIR/logrotate/gradido.conf.template > $SCRIPT_DIR/logrotate/gradido.conf -cp $SCRIPT_DIR/logrotate/gradido.conf /etc/logrotate.d/gradido.conf +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf +cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf chown root:root /etc/logrotate.d/gradido.conf # create db user @@ -96,7 +96,7 @@ export DB_USER=gradido export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); mysql < Date: Mon, 8 Jan 2024 16:45:53 +0100 Subject: [PATCH 11/85] fix bug --- deployment/hetzner_cloud/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index cdde55080..2116e37dd 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -15,7 +15,7 @@ set +o allexport # Load .env or .env.dist if not present # NOTE: all config values will be in process.env when starting # the services and will therefore take precedence over the .env -if [ -f "./.env" ]; then +if [ -f "$SCRIPT_PATH/.env" ]; then set -o allexport source $SCRIPT_PATH/.env set +o allexport From 1b3355a61011bf54b3ed21728ade8adc96519555 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 16:56:14 +0100 Subject: [PATCH 12/85] fix certbot --- deployment/bare_metal/start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index db67cc0d9..68934dbcf 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -65,7 +65,7 @@ ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/ sudo /etc/init.d/nginx restart # enable https if env variable has value https if [ "$URL_PROTOCOL" = "https" ]; then - certbot --nginx --non-interactive + certbot --nginx --non-interactive --domains $COMMUNITY_HOST fi # stop all services @@ -265,7 +265,7 @@ ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/ rm /etc/nginx/sites-enabled/update-page.conf sudo /etc/init.d/nginx restart if [ "$URL_PROTOCOL" = "https" ]; then - certbot --nginx --non-interactive + certbot --nginx --non-interactive --domains $COMMUNITY_HOST fi # keep the update log From 0540857af3d2c197df758400d6f6f122cf28df0f Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 17:26:59 +0100 Subject: [PATCH 13/85] update nginx code --- deployment/bare_metal/start.sh | 11 +++++------ deployment/hetzner_cloud/install.sh | 7 ++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 68934dbcf..554b947af 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -60,12 +60,12 @@ exec > >(tee -a $UPDATE_HTML) 2>&1 # configure nginx for the update-page echo 'Configuring nginx to serve the update-page' >> $UPDATE_HTML -rm /etc/nginx/sites-enabled/gradido.conf -ln -s /etc/nginx/sites-available/update-page.conf /etc/nginx/sites-enabled/ + +ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default sudo /etc/init.d/nginx restart # enable https if env variable has value https if [ "$URL_PROTOCOL" = "https" ]; then - certbot --nginx --non-interactive --domains $COMMUNITY_HOST + certbot install --nginx --non-interactive --cert-name $COMMUNITY_HOST --logs-dir ./log/ --work-dir . --config-dir . fi # stop all services @@ -261,11 +261,10 @@ done # let nginx showing gradido echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML -ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/ -rm /etc/nginx/sites-enabled/update-page.conf +ln -s $SCRIPT_PATH/nginx/sites-available/gradido.conf $SCRIPT_PATH/nginx/sites-enabled/default sudo /etc/init.d/nginx restart if [ "$URL_PROTOCOL" = "https" ]; then - certbot --nginx --non-interactive --domains $COMMUNITY_HOST + certbot install --nginx --non-interactive --cert-name $COMMUNITY_HOST --logs-dir ./log/ --work-dir . --config-dir . fi # keep the update log diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 2116e37dd..69224223a 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -62,9 +62,10 @@ echo "$SECURE_MYSQL" # Configure nginx rm /etc/nginx/sites-enabled/default envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf -ln -s $SCRIPT_DIR/nginx/sites-available/gradido.conf /etc/nginx/sites-available envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf -ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf /etc/nginx/sites-available +mkdir $SCRIPT_PATH/nginx/sites-enabled +ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default +ln -s $SCRIPT_PATH/nginx/sites-enabled/default /etc/nginx/sites-enabled ln -s $SCRIPT_PATH/nginx/common /etc/nginx/ rmdir /etc/nginx/conf.d ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ @@ -128,4 +129,4 @@ crontab -l | { cat; echo "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm crontab -l | { cat; echo "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null"; } | crontab - # Start gradido # Note: on first startup some errors will occur - nothing serious -$SCRIPT_PATH/start.sh \ No newline at end of file +sudo -u gradido $SCRIPT_PATH/start.sh \ No newline at end of file From bf1a6b8565cd9db4e74bf4bca0d8789fbdb1dfd5 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 17:47:42 +0100 Subject: [PATCH 14/85] use txt file for start cron jobs --- deployment/hetzner_cloud/crontabs.txt | 38 +++++++++++++++++++++++++++ deployment/hetzner_cloud/install.sh | 11 ++++---- 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 deployment/hetzner_cloud/crontabs.txt diff --git a/deployment/hetzner_cloud/crontabs.txt b/deployment/hetzner_cloud/crontabs.txt new file mode 100644 index 000000000..c798b58c4 --- /dev/null +++ b/deployment/hetzner_cloud/crontabs.txt @@ -0,0 +1,38 @@ +# Edit this file to introduce tasks to be run by cron. +# +# Each task to run has to be defined through a single line +# indicating with different fields when the task will be run +# and what command to run for the task +# +# To define the time you can provide concrete values for +# minute (m), hour (h), day of month (dom), month (mon), +# and day of week (dow) or use '*' in these fields (for 'any'). +# +# Notice that tasks will be started based on the cron's system +# daemon's notion of time and timezones. +# +# Output of the crontab jobs (including errors) is sent through +# email to the user the crontab file belongs to (unless redirected). +# +# For example, you can run a backup of all your user accounts +# at 5 a.m every week with: +# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ +# +# For more information see the manual pages of crontab(5) and cron(8) +# +# m h dom mon dow command + +# `yarn` creates output in `/tmp` directory. This output is generated whenever `yarn start` is called. +# This is especially problematic on staging systems where instable versions are automatically deployed which can lead to an ever restarting, +# hence generating a lot of yarn output. +# the following hourly cron clean the /tmp folder +0 * * * * find /tmp -name "yarn--*" -exec rm -r {} \; > /dev/null + +# cronjob for a daily db backup at 3:00am +0 3 * * * ~/gradido/deployment/bare_metal/backup.sh + +# cronjob for a daily logfile clearance at 3:15 +# remove all log files older than 30 days +15 3 * * * ~/gradido/deployment/bare_metal/removeLogFiles.sh + + diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 69224223a..f39ce6c32 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -9,6 +9,8 @@ systemctl start systemd-timesyncd set -o allexport SCRIPT_PATH=$(realpath ../bare_metal) SCRIPT_DIR=$(dirname $SCRIPT_PATH) +LOCAL_SCRIPT_PATH=$(realpath $0) +LOCAL_SCRIPT_DIR=$(dirname $SCRIPT_PATH) PROJECT_ROOT=$SCRIPT_DIR/.. set +o allexport @@ -121,12 +123,9 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env # Configure federation envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env -# create cronjob to delete yarn output in /tmp -# crontab -e -# hourly job: 0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null -crontab -l | { cat; echo "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null"; } | crontab - -# daily job: 0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null -crontab -l | { cat; echo "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null"; } | crontab - +# create cronjob to delete yarn output in /tmp and for making backups regulary +sudo -u gradido crontab < $LOCAL_SCRIPT_PATH/crontabs.txt + # Start gradido # Note: on first startup some errors will occur - nothing serious sudo -u gradido $SCRIPT_PATH/start.sh \ No newline at end of file From ceb84a2e55c7f5dc01064fb199da1e2c6ed5c2c3 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 20:42:32 +0100 Subject: [PATCH 15/85] update ssl and nginx setup, change node version install strategy --- deployment/bare_metal/.env.dist | 6 + .../sites-available/gradido.conf.ssl.template | 128 ++++++++++++++++++ .../update-page.conf.ssl.template | 37 +++++ deployment/bare_metal/start.sh | 28 ++-- deployment/hetzner_cloud/install.sh | 11 +- 5 files changed, 194 insertions(+), 16 deletions(-) create mode 100644 deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template create mode 100644 deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 59cbf042e..3ce9b4cb5 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -91,6 +91,12 @@ META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" # update page shown while updating gradido # page will be fed with status changes NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page +# NGINX SSL Setup with certbot +# will be generated by start.sh with $COMMUNITY_HOST, only need to set manual if setup differ from default +#NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/gddhost.tld/fullchain.pem +#NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/gddhost.tld/privkey.pem +NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem +NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf # LEGACY NGINX_REWRITE_LEGACY_URLS=false diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template new file mode 100644 index 000000000..a99327745 --- /dev/null +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -0,0 +1,128 @@ +server { + if ($host = $NGINX_SERVER_NAME) { + return 301 https://$host$request_uri; + } + + server_name $NGINX_SERVER_NAME; + listen 80; + listen [::]:80; + return 404; +} + +server { + server_name $NGINX_SERVER_NAME; + + listen [::]:443 ssl ipv6only=on; + listen 443 ssl; + ssl_certificate $NGINX_SSL_CERTIFICATE; + ssl_certificate_key $NGINX_SSL_CERTIFICATE_KEY; + include $NGINX_SSL_INCLUDE; + ssl_dhparam $NGINX_SSL_DHPARAM; + + include /etc/nginx/common/protect.conf; + include /etc/nginx/common/protect_add_header.conf; + + #gzip_static on; + gzip on; + gzip_proxied any; + gzip_types + text/css + text/javascript + text/xml + text/plain + application/javascript + application/x-javascript + application/json; + + # Legacy URLS + set $REWRITE_LEGACY_URLS "$NGINX_REWRITE_LEGACY_URLS"; + if ($REWRITE_LEGACY_URLS = 'true') { + rewrite ^/vue/?(.*)$ /$1 permanent; + } + + # Frontend (default) + location / { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:3000; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.frontend.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.frontend.log warn; + } + + # Backend + location /graphql { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:4000; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.backend.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn; + } + + # Backend webhooks + location /hook { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:4000/hook; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.backend.hook.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.backend.hook.log warn; + } + + # Webhook reverse proxy + location /hooks/ { + proxy_pass http://127.0.0.1:9000/hooks/; + + access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn; + } + + # Admin Frontend + location /admin { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:8080/; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; + } + + # Federation + $FEDERATION_NGINX_CONF + + # TODO this could be a performance optimization + #location /vue { + # alias /var/www/html/gradido/frontend/build; + # index index.html; + # + # location ~* \.(png)$ { + # expires 39d; + # } + # try_files $uri $uri/ /index.html = 404; + #} +} \ No newline at end of file diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template new file mode 100644 index 000000000..ddcb9ffc1 --- /dev/null +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -0,0 +1,37 @@ + +server { + if ($host = $NGINX_SERVER_NAME) { + return 301 https://$host$request_uri; + } + + server_name $NGINX_SERVER_NAME; + listen 80; + listen [::]:80; + return 404; +} +server { + server_name $NGINX_SERVER_NAME; + + listen [::]:443 ssl ipv6only=on; + listen 443 ssl; + ssl_certificate $NGINX_SSL_CERTIFICATE; + ssl_certificate_key $NGINX_SSL_CERTIFICATE_KEY; + include $NGINX_SSL_INCLUDE; + ssl_dhparam $NGINX_SSL_DHPARAM; + + include /etc/nginx/common/protect.conf; + include /etc/nginx/common/protect_add_header.conf; + + gzip on; + + root $NGINX_UPDATE_PAGE_ROOT; + index updating.html; + + location / { + try_files /updating.html =404; + } + + access_log $GRADIDO_LOG_PATH/nginx-access.update-page.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.update-page.log warn; +} + diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 554b947af..dd185861e 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -41,6 +41,10 @@ else set +o allexport fi +# set env variables dynamic if not already set in .env or .env.dist +: ${NGINX_SSL_CERTIFICATE:=/etc/letsencrypt/live/$COMMUNITY_HOST/fullchain.pem} +: ${NGINX_SSL_CERTIFICATE_KEY:=/etc/letsencrypt/live/$COMMUNITY_HOST/privkey.pem} + # lock start if [ -f $LOCK_FILE ] ; then echo "Already building!" @@ -60,13 +64,8 @@ exec > >(tee -a $UPDATE_HTML) 2>&1 # configure nginx for the update-page echo 'Configuring nginx to serve the update-page' >> $UPDATE_HTML - -ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default +ln -sf $SCRIPT_DIR/nginx/sites-available/update-page.conf $SCRIPT_DIR/nginx/sites-enabled/default sudo /etc/init.d/nginx restart -# enable https if env variable has value https -if [ "$URL_PROTOCOL" = "https" ]; then - certbot install --nginx --non-interactive --cert-name $COMMUNITY_HOST --logs-dir ./log/ --work-dir . --config-dir . -fi # stop all services echo 'Stop and delete all Gradido services' >> $UPDATE_HTML @@ -110,7 +109,11 @@ export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locat # *** 3rd generate gradido nginx config including federation modules per api-version echo 'Generate new gradido nginx config' >> $UPDATE_HTML -envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/gradido.conf.template > $NGINX_CONFIG_DIR/gradido.conf.tmp +case "$URL_PROTOCOL" in + 'https') TEMPLATE_FILE="gradido.conf.ssl.template" ;; + *) TEMPLATE_FILE="gradido.conf.template" ;; +esac +envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp unset FEDERATION_NGINX_CONF envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/gradido.conf.tmp > $NGINX_CONFIG_DIR/gradido.conf rm $NGINX_CONFIG_DIR/gradido.conf.tmp @@ -118,7 +121,11 @@ rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations # Generate update-page.conf from template echo 'Generate new update-page nginx config' >> $UPDATE_HTML -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/update-page.conf.template > $NGINX_CONFIG_DIR/update-page.conf +case "$URL_PROTOCOL" in + 'https') TEMPLATE_FILE="update-page.conf.ssl.template" ;; + *) TEMPLATE_FILE="update-page.conf.template" ;; +esac +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/update-page.conf # Clean tmp folder - remove yarn files find /tmp -name "yarn--*" -exec rm -r {} \; @@ -261,11 +268,8 @@ done # let nginx showing gradido echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML -ln -s $SCRIPT_PATH/nginx/sites-available/gradido.conf $SCRIPT_PATH/nginx/sites-enabled/default +ln -sf $SCRIPT_DIR/nginx/sites-available/gradido.conf $SCRIPT_DIR/nginx/sites-enabled/default sudo /etc/init.d/nginx restart -if [ "$URL_PROTOCOL" = "https" ]; then - certbot install --nginx --non-interactive --cert-name $COMMUNITY_HOST --logs-dir ./log/ --work-dir . --config-dir . -fi # keep the update log cat $UPDATE_HTML >> $GRADIDO_LOG_PATH/update.$TODAY.log diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index f39ce6c32..05c73622c 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -73,11 +73,14 @@ rmdir /etc/nginx/conf.d ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ # setup https with certbot -certbot --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL +certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL -# Install node 16.x -curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - -apt-get install -y nodejs +# Install node 16. with nvm, with nodesource is depracted +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash +# Close and reopen your terminal to start using nvm or run the following to use it now: +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +nvm install 16 # first installed version will be set to default automatic # Install yarn curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - From 8b280285f6fa9b2b17d6e20faf0e0e6d75fe1f02 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 20:49:36 +0100 Subject: [PATCH 16/85] comment --- deployment/bare_metal/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 3ce9b4cb5..326392124 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -92,7 +92,7 @@ META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" # page will be fed with status changes NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page # NGINX SSL Setup with certbot -# will be generated by start.sh with $COMMUNITY_HOST, only need to set manual if setup differ from default +# will be generated by start.sh with $COMMUNITY_HOST, only need to setup manual if setup differ from default #NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/gddhost.tld/fullchain.pem #NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/gddhost.tld/privkey.pem NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem From b9da99c20c11f53f376862e78e62667767198837 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 8 Jan 2024 21:57:13 +0100 Subject: [PATCH 17/85] fix errors from testrun --- deployment/hetzner_cloud/README.md | 1 - deployment/hetzner_cloud/install.sh | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md index 9f0bb94e6..5a5ae3186 100644 --- a/deployment/hetzner_cloud/README.md +++ b/deployment/hetzner_cloud/README.md @@ -106,5 +106,4 @@ will remove it and ln ../bare_metal/nginx/conf.d ```bash cd ~/gradido/deployment/hetzner_cloud -sudo chmod +x ./install.sh sudo ./install.sh \ No newline at end of file diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 05c73622c..a18886eb6 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -65,7 +65,7 @@ echo "$SECURE_MYSQL" rm /etc/nginx/sites-enabled/default envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf -mkdir $SCRIPT_PATH/nginx/sites-enabled +sudo -u gradido mkdir $SCRIPT_PATH/nginx/sites-enabled ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default ln -s $SCRIPT_PATH/nginx/sites-enabled/default /etc/nginx/sites-enabled ln -s $SCRIPT_PATH/nginx/common /etc/nginx/ @@ -76,11 +76,11 @@ ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL # Install node 16. with nvm, with nodesource is depracted -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash +sudo -u gradido curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # Close and reopen your terminal to start using nvm or run the following to use it now: export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm -nvm install 16 # first installed version will be set to default automatic +sudo -u gradido nvm install 16 # first installed version will be set to default automatic # Install yarn curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - @@ -95,7 +95,6 @@ pm2 startup # Install logrotate envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf -chown root:root /etc/logrotate.d/gradido.conf # create db user export DB_USER=gradido @@ -107,27 +106,27 @@ mysql < $PROJECT_ROOT/database/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env # Configure backend export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env # Configure frontend -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env # Configure admin -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env # Configure dht-node export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env # Configure federation -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env +sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env # create cronjob to delete yarn output in /tmp and for making backups regulary -sudo -u gradido crontab < $LOCAL_SCRIPT_PATH/crontabs.txt +sudo -u gradido crontab < $LOCAL_SCRIPT_DIR/crontabs.txt # Start gradido # Note: on first startup some errors will occur - nothing serious From 9ef45c0b6a064a7a5d4e6efee3d47eac14996ed3 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Mon, 8 Jan 2024 22:29:52 +0100 Subject: [PATCH 18/85] updateUserInfo with gms attributes --- backend/src/apis/gms/model/GmsEnums.ts | 36 --------------- backend/src/apis/gms/model/GmsUser.ts | 6 ++- .../src/graphql/arg/UpdateUserInfosArgs.ts | 20 ++++++++- .../graphql/enum/GmsPublishLocationType.ts | 12 +++++ .../src/graphql/enum/GmsPublishNameType.ts | 14 ++++++ .../src/graphql/enum/GmsPublishPhoneType.ts | 12 +++++ backend/src/graphql/model/Location.ts | 31 +++++++++++++ .../src/graphql/resolver/UserResolver.test.ts | 45 ++++++++++++++++++- backend/src/graphql/resolver/UserResolver.ts | 15 ++++++- backend/src/graphql/scalar/Geometry.ts | 33 ++++++++++++++ backend/src/seeds/graphql/mutations.ts | 8 ++++ 11 files changed, 190 insertions(+), 42 deletions(-) delete mode 100644 backend/src/apis/gms/model/GmsEnums.ts create mode 100644 backend/src/graphql/enum/GmsPublishLocationType.ts create mode 100644 backend/src/graphql/enum/GmsPublishNameType.ts create mode 100644 backend/src/graphql/enum/GmsPublishPhoneType.ts create mode 100644 backend/src/graphql/model/Location.ts create mode 100644 backend/src/graphql/scalar/Geometry.ts diff --git a/backend/src/apis/gms/model/GmsEnums.ts b/backend/src/apis/gms/model/GmsEnums.ts deleted file mode 100644 index 1342327d1..000000000 --- a/backend/src/apis/gms/model/GmsEnums.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { registerEnumType } from 'type-graphql' - -export enum GmsPublishNameType { - GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0, - GMS_PUBLISH_NAME_INITIALS = 1, - GMS_PUBLISH_NAME_FIRST = 2, - GMS_PUBLISH_NAME_FIRST_INITIAL = 3, - GMS_PUBLISH_NAME_FULL = 4, -} - -registerEnumType(GmsPublishNameType, { - name: 'GmsPublishNameType', // this one is mandatory - description: 'Type of name publishing', // this one is optional -}) - -export enum GmsPublishPhoneType { - GMS_PUBLISH_PHONE_NOTHING = 0, - GMS_PUBLISH_PHONE_COUNTRY = 1, - GMS_PUBLISH_PHONE_FULL = 2, -} - -registerEnumType(GmsPublishPhoneType, { - name: 'GmsPublishPhoneType', // this one is mandatory - description: 'Type of Phone publishing', // this one is optional -}) - -export enum GmsLocationType { - GMS_LOCATION_TYPE_EXACT = 0, - GMS_LOCATION_TYPE_APPROXIMATE = 1, - GMS_LOCATION_TYPE_RANDOM = 2, -} - -registerEnumType(GmsLocationType, { - name: 'GmsLocationType', // this one is mandatory - description: 'Type of location treatment in GMS', // this one is optional -}) diff --git a/backend/src/apis/gms/model/GmsUser.ts b/backend/src/apis/gms/model/GmsUser.ts index 2fad3bd1e..7f7db7660 100644 --- a/backend/src/apis/gms/model/GmsUser.ts +++ b/backend/src/apis/gms/model/GmsUser.ts @@ -1,6 +1,8 @@ import { User as dbUser } from '@entity/User' -import { GmsLocationType, GmsPublishNameType, GmsPublishPhoneType } from './GmsEnums' +import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType' +import { GmsPublishNameType } from '@/graphql/enum/GmsPublishNameType' +import { GmsPublishPhoneType } from '@/graphql/enum/GmsPublishPhoneType' export class GmsUser { constructor(user: dbUser) { @@ -12,7 +14,7 @@ export class GmsUser { this.firstName = this.getGmsFirstName(user) this.lastName = this.getGmsLastName(user) this.alias = this.getGmsAlias(user) - this.type = GmsLocationType.GMS_LOCATION_TYPE_RANDOM + this.type = GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM this.location = null } diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index 6b2ab1032..ab1263eee 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -1,6 +1,8 @@ -import { IsBoolean, IsInt, IsString } from 'class-validator' +import { IsBoolean, IsInt, IsObject, IsString } from 'class-validator' import { ArgsType, Field, Int } from 'type-graphql' +import { Location } from '@model/Location' + @ArgsType() export class UpdateUserInfosArgs { @Field({ nullable: true }) @@ -38,4 +40,20 @@ export class UpdateUserInfosArgs { @Field({ nullable: true }) @IsBoolean() hideAmountGDT?: boolean + + @Field({ nullable: false }) + @IsBoolean() + gmsAllowed: boolean + + @Field(() => Int, { nullable: false }) + @IsInt() + gmsPublishName: number + + @Field(() => Location, { nullable: true }) + @IsObject() + gmsLocation?: Location | null + + @Field(() => Int, { nullable: false }) + @IsInt() + gmsPublishLocation: number } diff --git a/backend/src/graphql/enum/GmsPublishLocationType.ts b/backend/src/graphql/enum/GmsPublishLocationType.ts new file mode 100644 index 000000000..afb9c246d --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishLocationType.ts @@ -0,0 +1,12 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishLocationType { + GMS_LOCATION_TYPE_EXACT = 0, + GMS_LOCATION_TYPE_APPROXIMATE = 1, + GMS_LOCATION_TYPE_RANDOM = 2, +} + +registerEnumType(GmsPublishLocationType, { + name: 'GmsPublishLocationType', // this one is mandatory + description: 'Type of location treatment in GMS', // this one is optional +}) diff --git a/backend/src/graphql/enum/GmsPublishNameType.ts b/backend/src/graphql/enum/GmsPublishNameType.ts new file mode 100644 index 000000000..08aaaf8ef --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishNameType.ts @@ -0,0 +1,14 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishNameType { + GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0, + GMS_PUBLISH_NAME_INITIALS = 1, + GMS_PUBLISH_NAME_FIRST = 2, + GMS_PUBLISH_NAME_FIRST_INITIAL = 3, + GMS_PUBLISH_NAME_FULL = 4, +} + +registerEnumType(GmsPublishNameType, { + name: 'GmsPublishNameType', // this one is mandatory + description: 'Type of name publishing', // this one is optional +}) diff --git a/backend/src/graphql/enum/GmsPublishPhoneType.ts b/backend/src/graphql/enum/GmsPublishPhoneType.ts new file mode 100644 index 000000000..a9821d8ff --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishPhoneType.ts @@ -0,0 +1,12 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishPhoneType { + GMS_PUBLISH_PHONE_NOTHING = 0, + GMS_PUBLISH_PHONE_COUNTRY = 1, + GMS_PUBLISH_PHONE_FULL = 2, +} + +registerEnumType(GmsPublishPhoneType, { + name: 'GmsPublishPhoneType', // this one is mandatory + description: 'Type of Phone publishing', // this one is optional +}) diff --git a/backend/src/graphql/model/Location.ts b/backend/src/graphql/model/Location.ts new file mode 100644 index 000000000..281ee9ff4 --- /dev/null +++ b/backend/src/graphql/model/Location.ts @@ -0,0 +1,31 @@ +import { Point } from '@dbTools/typeorm' +import { ArgsType, Field, InputType, Int } from 'type-graphql' + +@InputType() +@ArgsType() +// @ObjectType() +export class Location { + constructor(lon: number, lat: number) { + this.longitude = lon + this.latitude = lat + } + + @Field(() => Int) + longitude: number + + @Field(() => Int) + latitude: number + + // point is no Field and not part of the graphql type + private point: Point + + public getPoint(): Point { + const pointStr = '{ "type": "Point", "coordinates": [' + .concat(this.longitude.toString()) + .concat(', ') + .concat(this.latitude.toString()) + .concat('] }') + this.point = JSON.parse(pointStr) as Point + return this.point + } +} diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index a4892496b..7a81b7017 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -16,6 +16,8 @@ import { ApolloServerTestClient } from 'apollo-server-testing' import { GraphQLError } from 'graphql' import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid' +import { GmsPublishLocationType } from '@enum/GmsPublishLocationType' +import { GmsPublishNameType } from '@enum/GmsPublishNameType' import { OptInType } from '@enum/OptInType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { RoleNames } from '@enum/RoleNames' @@ -1165,7 +1167,16 @@ describe('UserResolver', () => { it('throws an error', async () => { jest.clearAllMocks() resetToken() - await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }), + ).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('401 Unauthorized')], }), @@ -1190,7 +1201,16 @@ describe('UserResolver', () => { }) it('returns true', async () => { - await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }), + ).resolves.toEqual( expect.objectContaining({ data: { updateUserInfos: true, @@ -1207,6 +1227,9 @@ describe('UserResolver', () => { firstName: 'Benjamin', lastName: 'Blümchen', locale: 'en', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) await expect(User.find()).resolves.toEqual([ @@ -1244,6 +1267,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { alias: 'bibi_Bloxberg', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) await expect(User.find()).resolves.toEqual([ @@ -1263,6 +1289,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { locale: 'not-valid', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1287,6 +1316,9 @@ describe('UserResolver', () => { variables: { password: 'wrong password', passwordNew: 'Aa12345_', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1310,6 +1342,9 @@ describe('UserResolver', () => { variables: { password: 'Aa12345_', passwordNew: 'Aa12345', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1338,6 +1373,9 @@ describe('UserResolver', () => { variables: { password: 'Aa12345_', passwordNew: 'Bb12345_', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -2585,6 +2623,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { alias: 'bibi', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 45053bda4..fa00a4d57 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -547,10 +547,16 @@ export class UserResolver { passwordNew, hideAmountGDD, hideAmountGDT, + gmsAllowed, + gmsPublishName, + gmsLocation, + gmsPublishLocation, }: UpdateUserInfosArgs, @Ctx() context: Context, ): Promise { - logger.info(`updateUserInfos(${firstName}, ${lastName}, ${language}, ***, ***)...`) + logger.info( + `updateUserInfos(${firstName}, ${lastName}, ${language}, ***, ***, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})...`, + ) const user = getUser(context) if (firstName) { @@ -599,6 +605,13 @@ export class UserResolver { user.hideAmountGDT = hideAmountGDT } + user.gmsAllowed = gmsAllowed + user.gmsPublishName = gmsPublishName + if (gmsLocation) { + user.location = gmsLocation.getPoint() + } + user.gmsPublishLocation = gmsPublishLocation + const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') diff --git a/backend/src/graphql/scalar/Geometry.ts b/backend/src/graphql/scalar/Geometry.ts new file mode 100644 index 000000000..c2cd48fdb --- /dev/null +++ b/backend/src/graphql/scalar/Geometry.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { Geometry as DbGeometry } from '@dbTools/typeorm' +import { GraphQLScalarType, Kind } from 'graphql' + +import { Location } from '@model/Location' + +export const GeometryScalar = new GraphQLScalarType({ + name: 'Geometry', + description: + 'The `Geometry` scalar type to represent longitude and latitude values of a geo location', + + serialize(value: DbGeometry): Location { + // Check type of value + if (value.type !== 'Point') { + throw new Error(`GeometryScalar can only serialize Geometry type 'Point' values`) + } + + return new Location(value.coordinates[0], value.coordinates[1]) + }, + + parseValue(value): DbGeometry { + const geometry: DbGeometry = JSON.parse(value) as DbGeometry + return geometry + }, + + parseLiteral(ast) { + if (ast.kind !== Kind.STRING) { + throw new TypeError(`${String(ast)} is not a valid Geometry value.`) + } + + return JSON.parse(ast.value) as DbGeometry + }, +}) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 554cc4def..a658c84d7 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -34,6 +34,10 @@ export const updateUserInfos = gql` $locale: String $hideAmountGDD: Boolean $hideAmountGDT: Boolean + $gmsAllowed: Boolean! + $gmsPublishName: Int! + $gmsLocation: Location + $gmsPublishLocation: Int! ) { updateUserInfos( firstName: $firstName @@ -44,6 +48,10 @@ export const updateUserInfos = gql` language: $locale hideAmountGDD: $hideAmountGDD hideAmountGDT: $hideAmountGDT + gmsAllowed: $gmsAllowed + gmsPublishName: $gmsPublishName + gmsLocation: $gmsLocation + gmsPublishLocation: $gmsPublishLocation ) } ` From 6cf9ae3ae82c7f588777ab055f46462f6ae619c3 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 13:26:30 +0100 Subject: [PATCH 19/85] fix --- deployment/hetzner_cloud/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index a18886eb6..b1a3d482f 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -76,7 +76,7 @@ ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL # Install node 16. with nvm, with nodesource is depracted -sudo -u gradido curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash +sudo -u gradido bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash' # Close and reopen your terminal to start using nvm or run the following to use it now: export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm From df04b9e88e2bc1909f932ed94d3525cc66d0b427 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 14:15:36 +0100 Subject: [PATCH 20/85] update usage of yarn to make it compatible with nvm --- deployment/bare_metal/start.sh | 3 +++ deployment/hetzner_cloud/install.sh | 32 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index dd185861e..b68d5aea8 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -10,6 +10,9 @@ PROJECT_ROOT=$SCRIPT_DIR/../.. NGINX_CONFIG_DIR=$SCRIPT_DIR/nginx/sites-available set +o allexport +# enable nvm +export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + # NOTE: all config values will be in process.env when starting # the services and will therefore take precedence over the .env diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index b1a3d482f..ae1c106ca 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -14,6 +14,25 @@ LOCAL_SCRIPT_DIR=$(dirname $SCRIPT_PATH) PROJECT_ROOT=$SCRIPT_DIR/.. set +o allexport +# If install.sh will be called more than once +# We have to load the backend .env to get DB_USERNAME, DB_PASSWORD AND JWT_SECRET +# and the dht-node .env to get FEDERATION_DHT_SEED +export_var(){ + export $1=$(grep -v '^#' $PROJECT_ROOT/backend/.env | grep -e "$1" | sed -e 's/.*=//') + export $1=$(grep -v '^#' $PROJECT_ROOT/dht-node/.env | grep -e "$1" | sed -e 's/.*=//') +} + +if [ -f "$PROJECT_ROOT/backend/.env" ]; then + export_var 'DB_USER' + export_var 'DB_PASSWORD' + export_var 'JWT_SECRET' +fi + +if [ -f "$PROJECT_ROOT/dht-node/.env" ]; then + export_var 'FEDERATION_DHT_SEED' +fi + + # Load .env or .env.dist if not present # NOTE: all config values will be in process.env when starting # the services and will therefore take precedence over the .env @@ -78,19 +97,14 @@ certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST # Install node 16. with nvm, with nodesource is depracted sudo -u gradido bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash' # Close and reopen your terminal to start using nvm or run the following to use it now: -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm -sudo -u gradido nvm install 16 # first installed version will be set to default automatic +sudo -u gradido bash -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && nvm install 16' # first installed version will be set to default automatic # Install yarn -curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - -echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list -apt-get update -apt-get install -y yarn +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g yarn' # Install pm2 -yarn global add pm2 -pm2 startup +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g pm2 && pm2 startup' # Install logrotate envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf From fdfa423ab4eb9b7e134d3fd0b993813f0f4c8231 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 16:20:51 +0100 Subject: [PATCH 21/85] add logging views --- .../src/graphql/resolver/CommunityResolver.ts | 2 +- .../graphql/resolver/TransactionsResolver.ts | 11 +++- .../backendToDb/community/Community.role.ts | 9 ++- .../community/HomeCommunity.role.ts | 4 +- .../src/logging/AbstractLogging.view.ts | 49 +++++++++++++++ .../src/logging/AccountLogging.view.ts | 30 ++++++++++ .../logging/BackendTransactionLogging.view.ts | 30 ++++++++++ .../src/logging/CommunityLogging.view.ts | 24 ++++++++ .../src/logging/CommunityRootLogging.view.ts | 18 ++++++ .../logging/ConfirmBackendTransaction.view.ts | 20 +++++++ .../ConfirmedTransactionLogging.view.ts | 24 ++++++++ .../src/logging/DecayLogging.view.ts | 20 +++++++ .../logging/GradidoCreationLogging.view.ts | 18 ++++++ .../GradidoDeferredTransferLogging.view.ts | 18 ++++++ .../logging/GradidoTransactionLogging.view.ts | 29 +++++++++ .../logging/GradidoTransferLogging.view.ts | 18 ++++++ .../logging/GroupFriendsUpdateLogging.view.ts | 16 +++++ .../logging/RegisterAddressLogging.view.ts | 22 +++++++ .../src/logging/SignatureMapLogging.view.ts | 16 +++++ .../src/logging/SignaturePairLogging.view.ts | 17 ++++++ .../logging/TransactionBodyLogging.view.ts | 45 ++++++++++++++ .../logging/TransactionDraftLogging.view.ts | 24 ++++++++ .../src/logging/TransactionLogging.view.ts | 59 +++++++++++++++++++ .../src/logging/TransferAmountLogging.view.ts | 18 ++++++ .../src/logging/UserIdentifierLogging.view.ts | 17 ++++++ dlt-connector/src/logging/UserLogging.view.ts | 19 ++++++ .../src/{server => logging}/logger.ts | 0 dlt-connector/src/server/LogError.ts | 2 +- dlt-connector/src/server/createServer.ts | 3 +- dlt-connector/src/typeorm/DataSource.ts | 2 +- dlt-connector/src/utils/typeConverter.ts | 2 +- dlt-connector/test/testSetup.ts | 2 +- 32 files changed, 575 insertions(+), 13 deletions(-) create mode 100644 dlt-connector/src/logging/AbstractLogging.view.ts create mode 100644 dlt-connector/src/logging/AccountLogging.view.ts create mode 100644 dlt-connector/src/logging/BackendTransactionLogging.view.ts create mode 100644 dlt-connector/src/logging/CommunityLogging.view.ts create mode 100644 dlt-connector/src/logging/CommunityRootLogging.view.ts create mode 100644 dlt-connector/src/logging/ConfirmBackendTransaction.view.ts create mode 100644 dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts create mode 100644 dlt-connector/src/logging/DecayLogging.view.ts create mode 100644 dlt-connector/src/logging/GradidoCreationLogging.view.ts create mode 100644 dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts create mode 100644 dlt-connector/src/logging/GradidoTransactionLogging.view.ts create mode 100644 dlt-connector/src/logging/GradidoTransferLogging.view.ts create mode 100644 dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts create mode 100644 dlt-connector/src/logging/RegisterAddressLogging.view.ts create mode 100644 dlt-connector/src/logging/SignatureMapLogging.view.ts create mode 100644 dlt-connector/src/logging/SignaturePairLogging.view.ts create mode 100644 dlt-connector/src/logging/TransactionBodyLogging.view.ts create mode 100644 dlt-connector/src/logging/TransactionDraftLogging.view.ts create mode 100644 dlt-connector/src/logging/TransactionLogging.view.ts create mode 100644 dlt-connector/src/logging/TransferAmountLogging.view.ts create mode 100644 dlt-connector/src/logging/UserIdentifierLogging.view.ts create mode 100644 dlt-connector/src/logging/UserLogging.view.ts rename dlt-connector/src/{server => logging}/logger.ts (100%) diff --git a/dlt-connector/src/graphql/resolver/CommunityResolver.ts b/dlt-connector/src/graphql/resolver/CommunityResolver.ts index d4bbeb28e..741de2e6d 100644 --- a/dlt-connector/src/graphql/resolver/CommunityResolver.ts +++ b/dlt-connector/src/graphql/resolver/CommunityResolver.ts @@ -9,8 +9,8 @@ import { TransactionResult } from '@model/TransactionResult' import { CommunityRepository } from '@/data/Community.repository' import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' +import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { logger } from '@/server/logger' import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' @Resolver() diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 10b55573e..cc20a1034 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,9 +1,11 @@ -import { Resolver, Arg, Mutation } from 'type-graphql' - import { TransactionDraft } from '@input/TransactionDraft' +import { Resolver, Arg, Mutation } from 'type-graphql' import { TransactionRepository } from '@/data/Transaction.repository' import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransationRecipe.context' +import { BackendTransactionLoggingView } from '@/logging/BackendTransactionLogging.view' +import { logger } from '@/logging/logger' +import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { LogError } from '@/server/LogError' import { TransactionError } from '../model/TransactionError' @@ -35,8 +37,13 @@ export class TransactionResolver { } const backendTransaction = transactionRecipe.backendTransactions[0] backendTransaction.transactionId = transactionRecipe.id + logger.debug( + 'store backendTransaction', + new BackendTransactionLoggingView(backendTransaction), + ) await backendTransaction.save() } else { + logger.debug('store transaction recipe', new TransactionLoggingView(transactionRecipe)) // we can store the transaction and with that automatic the backend transaction await transactionRecipe.save() } diff --git a/dlt-connector/src/interactions/backendToDb/community/Community.role.ts b/dlt-connector/src/interactions/backendToDb/community/Community.role.ts index 30d91bfed..2b1514ef2 100644 --- a/dlt-connector/src/interactions/backendToDb/community/Community.role.ts +++ b/dlt-connector/src/interactions/backendToDb/community/Community.role.ts @@ -3,7 +3,8 @@ import { Community } from '@entity/Community' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/server/logger' +import { CommunityLoggingView } from '@/logging/CommunityLogging.view' +import { logger } from '@/logging/logger' export abstract class CommunityRole { protected self: Community @@ -17,9 +18,11 @@ export abstract class CommunityRole { this.self.foreign = communityDraft.foreign } - public store(): Promise { + public async store(): Promise { try { - return this.self.save() + const community = await this.self.save() + logger.debug('store community', new CommunityLoggingView(community)) + return community } catch (error) { logger.error('error saving new community into db: %s', error) throw new TransactionError(TransactionErrorType.DB_ERROR, 'error saving community into db') diff --git a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts index 256cfe1a5..7a4798368 100644 --- a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts +++ b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts @@ -8,7 +8,8 @@ import { Mnemonic } from '@/data/Mnemonic' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/server/logger' +import { CommunityLoggingView } from '@/logging/CommunityLogging.view' +import { logger } from '@/logging/logger' import { getDataSource } from '@/typeorm/DataSource' import { CreateTransactionRecipeContext } from '../transaction/CreateTransationRecipe.context' @@ -38,6 +39,7 @@ export class HomeCommunityRole extends CommunityRole { return await getDataSource().transaction(async (transactionalEntityManager) => { const community = await transactionalEntityManager.save(this.self) await transactionalEntityManager.save(this.transactionRecipe) + logger.debug('store home community', new CommunityLoggingView(community)) return community }) } catch (error) { diff --git a/dlt-connector/src/logging/AbstractLogging.view.ts b/dlt-connector/src/logging/AbstractLogging.view.ts new file mode 100644 index 000000000..3d9c2f811 --- /dev/null +++ b/dlt-connector/src/logging/AbstractLogging.view.ts @@ -0,0 +1,49 @@ +import util from 'util' + +import { Decimal } from 'decimal.js-light' + +import { Timestamp } from '@/data/proto/3_3/Timestamp' +import { TimestampSeconds } from '@/data/proto/3_3/TimestampSeconds' +import { timestampSecondsToDate, timestampToDate } from '@/utils/typeConverter' + +export abstract class AbstractLoggingView { + protected bufferStringFormat: BufferEncoding = 'hex' + + // This function gets called automatically when JSON.stringify() is called on this class instance + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public abstract toJSON(): any + public toString(): string { + return JSON.stringify(this.toJSON(), null, 2) + } + + // called form console.log or log4js logging functions + [util.inspect.custom](): string { + return this.toString() + } + + public dateToString(date: Date | undefined | null): string | undefined { + if (date) { + return date.toISOString() + } + return undefined + } + + public decimalToString(number: Decimal | undefined | null): string | undefined { + if (number) { + return number.toString() + } + return undefined + } + + public timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { + if (timestamp && timestamp.seconds) { + return timestampSecondsToDate(timestamp).toISOString() + } + } + + public timestampToDateString(timestamp: Timestamp): string | undefined { + if (timestamp && (timestamp.seconds || timestamp.nanoSeconds)) { + return timestampToDate(timestamp).toISOString() + } + } +} diff --git a/dlt-connector/src/logging/AccountLogging.view.ts b/dlt-connector/src/logging/AccountLogging.view.ts new file mode 100644 index 000000000..e4f00e272 --- /dev/null +++ b/dlt-connector/src/logging/AccountLogging.view.ts @@ -0,0 +1,30 @@ +import { Account } from '@entity/Account' + +import { AddressType } from '@/data/proto/3_3/enum/AddressType' +import { getEnumValue } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class AccountLoggingView extends AbstractLoggingView { + public constructor(private account: Account) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.account.id, + user: this.account.user ? new UserLoggingView(this.account.user).toJSON() : null, + derivationIndex: this.account.derivationIndex, + derive2pubkey: this.account.derive2Pubkey.toString(this.bufferStringFormat), + type: getEnumValue(AddressType, this.account.type), + createdAt: this.dateToString(this.account.createdAt), + confirmedAt: this.dateToString(this.account.confirmedAt), + balanceOnConfirmation: this.decimalToString(this.account.balanceOnConfirmation), + balanceConfirmedAt: this.dateToString(this.account.balanceConfirmedAt), + balanceOnCreation: this.decimalToString(this.account.balanceOnCreation), + balanceCreatedAt: this.dateToString(this.account.balanceCreatedAt), + } + } +} diff --git a/dlt-connector/src/logging/BackendTransactionLogging.view.ts b/dlt-connector/src/logging/BackendTransactionLogging.view.ts new file mode 100644 index 000000000..d21c765aa --- /dev/null +++ b/dlt-connector/src/logging/BackendTransactionLogging.view.ts @@ -0,0 +1,30 @@ +import { BackendTransaction } from '@entity/BackendTransaction' + +import { InputTransactionType } from '@/graphql/enum/InputTransactionType' +import { getEnumValue } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' + +export class BackendTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: BackendTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(showTransaction = true): any { + return { + id: this.self.id, + backendTransactionId: this.self.backendTransactionId, + transaction: + showTransaction && this.self.transaction + ? new TransactionLoggingView(this.self.transaction).toJSON(false) + : undefined, + type: getEnumValue(InputTransactionType, this.self.typeId), + balance: this.decimalToString(this.self.balance), + createdAt: this.dateToString(this.self.createdAt), + confirmedAt: this.dateToString(this.self.confirmedAt), + verifiedOnBackend: this.self.verifiedOnBackend, + } + } +} diff --git a/dlt-connector/src/logging/CommunityLogging.view.ts b/dlt-connector/src/logging/CommunityLogging.view.ts new file mode 100644 index 000000000..22f0a4597 --- /dev/null +++ b/dlt-connector/src/logging/CommunityLogging.view.ts @@ -0,0 +1,24 @@ +import { Community } from '@entity/Community' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { AccountLoggingView } from './AccountLogging.view' + +export class CommunityLoggingView extends AbstractLoggingView { + public constructor(private self: Community) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + iotaTopic: this.self.iotaTopic, + foreign: this.self.foreign, + publicKey: this.self.rootPubkey?.toString(this.bufferStringFormat), + createdAt: this.dateToString(this.self.createdAt), + confirmedAt: this.dateToString(this.self.confirmedAt), + aufAccount: this.self.aufAccount ? new AccountLoggingView(this.self.aufAccount) : undefined, + gmwAccount: this.self.gmwAccount ? new AccountLoggingView(this.self.gmwAccount) : undefined, + } + } +} diff --git a/dlt-connector/src/logging/CommunityRootLogging.view.ts b/dlt-connector/src/logging/CommunityRootLogging.view.ts new file mode 100644 index 000000000..ba2869755 --- /dev/null +++ b/dlt-connector/src/logging/CommunityRootLogging.view.ts @@ -0,0 +1,18 @@ +import { CommunityRoot } from '@/data/proto/3_3/CommunityRoot' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class CommunityRootLoggingView extends AbstractLoggingView { + public constructor(private self: CommunityRoot) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + rootPubkey: Buffer.from(this.self.rootPubkey).toString(this.bufferStringFormat), + gmwPubkey: Buffer.from(this.self.gmwPubkey).toString(this.bufferStringFormat), + aufPubkey: Buffer.from(this.self.aufPubkey).toString(this.bufferStringFormat), + } + } +} diff --git a/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts b/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts new file mode 100644 index 000000000..667d290dd --- /dev/null +++ b/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts @@ -0,0 +1,20 @@ +import { ConfirmBackendTransaction } from '@/graphql/model/ConfirmBackendTransaction' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class ConfirmBackendTransactionView extends AbstractLoggingView { + public constructor(private self: ConfirmBackendTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + transactionId: this.self.transactionId, + iotaMessageId: this.self.iotaMessageId, + gradidoId: this.self.gradidoId, + balance: this.decimalToString(this.self.balance), + balanceDate: this.self.balanceDate, + } + } +} diff --git a/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts b/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts new file mode 100644 index 000000000..8e894a35a --- /dev/null +++ b/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts @@ -0,0 +1,24 @@ +import { ConfirmedTransaction } from '@/data/proto/3_3/ConfirmedTransaction' +import { timestampSecondsToDate } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { GradidoTransactionLoggingView } from './GradidoTransactionLogging.view' + +export class ConfirmedTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: ConfirmedTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id.toString(), + transaction: new GradidoTransactionLoggingView(this.self.transaction).toJSON(), + confirmedAt: this.dateToString(timestampSecondsToDate(this.self.confirmedAt)), + versionNumber: this.self.versionNumber, + runningHash: Buffer.from(this.self.runningHash).toString(this.bufferStringFormat), + messageId: Buffer.from(this.self.messageId).toString(this.bufferStringFormat), + accountBalance: this.self.accountBalance, + } + } +} diff --git a/dlt-connector/src/logging/DecayLogging.view.ts b/dlt-connector/src/logging/DecayLogging.view.ts new file mode 100644 index 000000000..cf7817f58 --- /dev/null +++ b/dlt-connector/src/logging/DecayLogging.view.ts @@ -0,0 +1,20 @@ +import { Decay } from '@/graphql/model/Decay' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class DecayLoggingView extends AbstractLoggingView { + public constructor(private self: Decay) { + super() + } + + public toJSON() { + return { + balance: this.decimalToString(this.self.balance), + decay: this.decimalToString(this.self.decay), + roundedDecay: this.decimalToString(this.self.roundedDecay), + start: this.dateToString(this.self.start), + end: this.dateToString(this.self.end), + duration: this.self.duration + 's', + } + } +} diff --git a/dlt-connector/src/logging/GradidoCreationLogging.view.ts b/dlt-connector/src/logging/GradidoCreationLogging.view.ts new file mode 100644 index 000000000..43e14b887 --- /dev/null +++ b/dlt-connector/src/logging/GradidoCreationLogging.view.ts @@ -0,0 +1,18 @@ +import { GradidoCreation } from '@/data/proto/3_3/GradidoCreation' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransferAmountLoggingView } from './TransferAmountLogging.view' + +export class GradidoCreationLoggingView extends AbstractLoggingView { + public constructor(private self: GradidoCreation) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + recipient: new TransferAmountLoggingView(this.self.recipient).toJSON(), + targetDate: this.timestampSecondsToDateString(this.self.targetDate), + } + } +} diff --git a/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts b/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts new file mode 100644 index 000000000..89a1f1a29 --- /dev/null +++ b/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts @@ -0,0 +1,18 @@ +import { GradidoDeferredTransfer } from '@/data/proto/3_3/GradidoDeferredTransfer' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { GradidoTransferLoggingView } from './GradidoTransferLogging.view' + +export class GradidoDeferredTransferLoggingView extends AbstractLoggingView { + public constructor(private self: GradidoDeferredTransfer) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + ...new GradidoTransferLoggingView(this.self.transfer).toJSON(), + ...{ timeout: this.timestampSecondsToDateString(this.self.timeout) }, + } + } +} diff --git a/dlt-connector/src/logging/GradidoTransactionLogging.view.ts b/dlt-connector/src/logging/GradidoTransactionLogging.view.ts new file mode 100644 index 000000000..f23c0b05e --- /dev/null +++ b/dlt-connector/src/logging/GradidoTransactionLogging.view.ts @@ -0,0 +1,29 @@ +import { GradidoTransaction } from '@/data/proto/3_3/GradidoTransaction' +import { TransactionBody } from '@/data/proto/3_3/TransactionBody' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { SignatureMapLoggingView } from './SignatureMapLogging.view' +import { TransactionBodyLoggingView } from './TransactionBodyLogging.view' + +export class GradidoTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: GradidoTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + let transactionBody: TransactionBody | null | unknown = null + try { + transactionBody = new TransactionBodyLoggingView(this.self.getTransactionBody()) + } catch (e) { + transactionBody = e + } + return { + sigMap: new SignatureMapLoggingView(this.self.sigMap).toJSON(), + bodyBytes: transactionBody, + parentMessageId: this.self.parentMessageId + ? Buffer.from(this.self.parentMessageId).toString(this.bufferStringFormat) + : undefined, + } + } +} diff --git a/dlt-connector/src/logging/GradidoTransferLogging.view.ts b/dlt-connector/src/logging/GradidoTransferLogging.view.ts new file mode 100644 index 000000000..84b5fe604 --- /dev/null +++ b/dlt-connector/src/logging/GradidoTransferLogging.view.ts @@ -0,0 +1,18 @@ +import { GradidoTransfer } from '@/data/proto/3_3/GradidoTransfer' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransferAmountLoggingView } from './TransferAmountLogging.view' + +export class GradidoTransferLoggingView extends AbstractLoggingView { + public constructor(private self: GradidoTransfer) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + sender: new TransferAmountLoggingView(this.self.sender), + recipient: Buffer.from(this.self.recipient).toString(this.bufferStringFormat), + } + } +} diff --git a/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts b/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts new file mode 100644 index 000000000..8d1159d82 --- /dev/null +++ b/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts @@ -0,0 +1,16 @@ +import { GroupFriendsUpdate } from '@/data/proto/3_3/GroupFriendsUpdate' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class GroupFriendsUpdateLoggingView extends AbstractLoggingView { + public constructor(private self: GroupFriendsUpdate) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + colorFusion: this.self.colorFusion, + } + } +} diff --git a/dlt-connector/src/logging/RegisterAddressLogging.view.ts b/dlt-connector/src/logging/RegisterAddressLogging.view.ts new file mode 100644 index 000000000..bb857e2b8 --- /dev/null +++ b/dlt-connector/src/logging/RegisterAddressLogging.view.ts @@ -0,0 +1,22 @@ +import { AddressType } from '@/data/proto/3_3/enum/AddressType' +import { RegisterAddress } from '@/data/proto/3_3/RegisterAddress' +import { getEnumValue } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class RegisterAddressLoggingView extends AbstractLoggingView { + public constructor(private self: RegisterAddress) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + userPublicKey: Buffer.from(this.self.userPubkey).toString(this.bufferStringFormat), + addressType: getEnumValue(AddressType, this.self.addressType), + nameHash: Buffer.from(this.self.nameHash).toString(this.bufferStringFormat), + accountPublicKey: Buffer.from(this.self.accountPubkey).toString(this.bufferStringFormat), + derivationIndex: this.self.derivationIndex, + } + } +} diff --git a/dlt-connector/src/logging/SignatureMapLogging.view.ts b/dlt-connector/src/logging/SignatureMapLogging.view.ts new file mode 100644 index 000000000..89c331a64 --- /dev/null +++ b/dlt-connector/src/logging/SignatureMapLogging.view.ts @@ -0,0 +1,16 @@ +import { SignatureMap } from '@/data/proto/3_3/SignatureMap' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { SignaturePairLoggingView } from './SignaturePairLogging.view' + +export class SignatureMapLoggingView extends AbstractLoggingView { + public constructor(private self: SignatureMap) { + super() + } + + public toJSON() { + return { + sigPair: this.self.sigPair.map((value) => new SignaturePairLoggingView(value).toJSON()), + } + } +} diff --git a/dlt-connector/src/logging/SignaturePairLogging.view.ts b/dlt-connector/src/logging/SignaturePairLogging.view.ts new file mode 100644 index 000000000..c3317a5ec --- /dev/null +++ b/dlt-connector/src/logging/SignaturePairLogging.view.ts @@ -0,0 +1,17 @@ +import { SignaturePair } from '@/data/proto/3_3/SignaturePair' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class SignaturePairLoggingView extends AbstractLoggingView { + public constructor(private self: SignaturePair) { + super() + } + + public toJSON() { + return { + pubkey: Buffer.from(this.self.pubKey).toString(this.bufferStringFormat), + signature: + Buffer.from(this.self.signature).subarray(0, 31).toString(this.bufferStringFormat) + '..', + } + } +} diff --git a/dlt-connector/src/logging/TransactionBodyLogging.view.ts b/dlt-connector/src/logging/TransactionBodyLogging.view.ts new file mode 100644 index 000000000..9e08bbfa6 --- /dev/null +++ b/dlt-connector/src/logging/TransactionBodyLogging.view.ts @@ -0,0 +1,45 @@ +import { getCrossGroupTypeEnumValue } from '@/data/proto/3_3/enum/CrossGroupType' +import { TransactionBody } from '@/data/proto/3_3/TransactionBody' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { CommunityRootLoggingView } from './CommunityRootLogging.view' +import { GradidoCreationLoggingView } from './GradidoCreationLogging.view' +import { GradidoDeferredTransferLoggingView } from './GradidoDeferredTransferLogging.view' +import { GradidoTransferLoggingView } from './GradidoTransferLogging.view' +import { GroupFriendsUpdateLoggingView } from './GroupFriendsUpdateLogging.view' +import { RegisterAddressLoggingView } from './RegisterAddressLogging.view' + +export class TransactionBodyLoggingView extends AbstractLoggingView { + public constructor(private self: TransactionBody) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + memo: this.self.memo, + createdAt: this.timestampToDateString(this.self.createdAt), + versionNumber: this.self.versionNumber, + type: getCrossGroupTypeEnumValue(this.self.type), + otherGroup: this.self.otherGroup, + transfer: this.self.transfer + ? new GradidoTransferLoggingView(this.self.transfer).toJSON() + : undefined, + creation: this.self.creation + ? new GradidoCreationLoggingView(this.self.creation).toJSON() + : undefined, + groupFriendsUpdate: this.self.groupFriendsUpdate + ? new GroupFriendsUpdateLoggingView(this.self.groupFriendsUpdate).toJSON() + : undefined, + registerAddress: this.self.registerAddress + ? new RegisterAddressLoggingView(this.self.registerAddress).toJSON() + : undefined, + deferredTransfer: this.self.deferredTransfer + ? new GradidoDeferredTransferLoggingView(this.self.deferredTransfer).toJSON() + : undefined, + communityRoot: this.self.communityRoot + ? new CommunityRootLoggingView(this.self.communityRoot).toJSON() + : undefined, + } + } +} diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts new file mode 100644 index 000000000..f2115f591 --- /dev/null +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -0,0 +1,24 @@ +import { InputTransactionType } from '@/graphql/enum/InputTransactionType' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { getEnumValue } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserIdentifierLoggingView } from './UserIdentifierLogging.view' + +export class TransactionDraftLoggingView extends AbstractLoggingView { + public constructor(private self: TransactionDraft) { + super() + } + + public toJSON() { + return { + senderUser: new UserIdentifierLoggingView(this.self.senderUser).toJSON(), + recipientUser: new UserIdentifierLoggingView(this.self.recipientUser).toJSON(), + backendTransactionId: this.self.backendTransactionId, + amount: this.decimalToString(this.self.amount), + type: getEnumValue(InputTransactionType, this.self.type), + createdAt: this.self.createdAt, + targetDate: this.self.targetDate, + } + } +} diff --git a/dlt-connector/src/logging/TransactionLogging.view.ts b/dlt-connector/src/logging/TransactionLogging.view.ts new file mode 100644 index 000000000..38443024d --- /dev/null +++ b/dlt-connector/src/logging/TransactionLogging.view.ts @@ -0,0 +1,59 @@ +import { Transaction } from '@entity/Transaction' + +import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' +import { LogError } from '@/server/LogError' +import { getEnumValue } from '@/utils/typeConverter' + +import { AbstractLoggingView } from './AbstractLogging.view' +import { AccountLoggingView } from './AccountLogging.view' +import { BackendTransactionLoggingView } from './BackendTransactionLogging.view' +import { CommunityLoggingView } from './CommunityLogging.view' + +export class TransactionLoggingView extends AbstractLoggingView { + public constructor(private self: Transaction) { + super() + if (this.self.community === undefined) { + throw new LogError('sender community is zero') + } + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(showBackendTransactions = true): any { + return { + id: this.self.id, + nr: this.self.nr, + bodyBytesLength: this.self.bodyBytes.length, + createdAt: this.dateToString(this.self.createdAt), + confirmedAt: this.dateToString(this.self.confirmedAt), + protocolVersion: this.self.protocolVersion, + type: getEnumValue(TransactionType, this.self.type), + signature: this.self.signature.subarray(0, 31).toString(this.bufferStringFormat) + '..', + community: new CommunityLoggingView(this.self.community).toJSON(), + otherCommunity: this.self.otherCommunity + ? new CommunityLoggingView(this.self.otherCommunity) + : undefined, + iotaMessageId: this.self.iotaMessageId + ? this.self.iotaMessageId.toString(this.bufferStringFormat) + : undefined, + signingAccount: this.self.signingAccount + ? new AccountLoggingView(this.self.signingAccount) + : undefined, + recipientAccount: this.self.recipientAccount + ? new AccountLoggingView(this.self.recipientAccount) + : undefined, + amount: this.decimalToString(this.self.amount), + accountBalanceOnCreation: this.decimalToString(this.self.accountBalanceOnCreation), + accountBalanceOnConfirmation: this.decimalToString(this.self.accountBalanceOnConfirmation), + runningHash: this.self.runningHash + ? this.self.runningHash.toString(this.bufferStringFormat) + : undefined, + iotaMilestone: this.self.iotaMilestone, + backendTransactions: + showBackendTransactions && this.self.backendTransactions + ? this.self.backendTransactions.map((backendTransaction) => + new BackendTransactionLoggingView(backendTransaction).toJSON(false), + ) + : undefined, + } + } +} diff --git a/dlt-connector/src/logging/TransferAmountLogging.view.ts b/dlt-connector/src/logging/TransferAmountLogging.view.ts new file mode 100644 index 000000000..8d320b99f --- /dev/null +++ b/dlt-connector/src/logging/TransferAmountLogging.view.ts @@ -0,0 +1,18 @@ +import { TransferAmount } from '@/data/proto/3_3/TransferAmount' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class TransferAmountLoggingView extends AbstractLoggingView { + public constructor(private self: TransferAmount) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + publicKey: Buffer.from(this.self.pubkey).toString(this.bufferStringFormat), + amount: this.self.amount, + communityId: this.self.communityId, + } + } +} diff --git a/dlt-connector/src/logging/UserIdentifierLogging.view.ts b/dlt-connector/src/logging/UserIdentifierLogging.view.ts new file mode 100644 index 000000000..b49fb604c --- /dev/null +++ b/dlt-connector/src/logging/UserIdentifierLogging.view.ts @@ -0,0 +1,17 @@ +import { UserIdentifier } from '@/graphql/input/UserIdentifier' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class UserIdentifierLoggingView extends AbstractLoggingView { + public constructor(private self: UserIdentifier) { + super() + } + + public toJSON() { + return { + uuid: this.self.uuid, + communityUuid: this.self.communityUuid, + accountNr: this.self.accountNr, + } + } +} diff --git a/dlt-connector/src/logging/UserLogging.view.ts b/dlt-connector/src/logging/UserLogging.view.ts new file mode 100644 index 000000000..4db4f61fd --- /dev/null +++ b/dlt-connector/src/logging/UserLogging.view.ts @@ -0,0 +1,19 @@ +import { User } from '@entity/User' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class UserLoggingView extends AbstractLoggingView { + public constructor(private user: User) { + super() + } + + public toJSON() { + return { + id: this.user.id, + gradidoId: this.user.gradidoID, + derive1Pubkey: this.user.derive1Pubkey.toString(this.bufferStringFormat), + createdAt: this.dateToString(this.user.createdAt), + confirmedAt: this.dateToString(this.user.confirmedAt), + } + } +} diff --git a/dlt-connector/src/server/logger.ts b/dlt-connector/src/logging/logger.ts similarity index 100% rename from dlt-connector/src/server/logger.ts rename to dlt-connector/src/logging/logger.ts diff --git a/dlt-connector/src/server/LogError.ts b/dlt-connector/src/server/LogError.ts index 8e145a0ef..69aca1978 100644 --- a/dlt-connector/src/server/LogError.ts +++ b/dlt-connector/src/server/LogError.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { logger } from './logger' +import { logger } from '@/logging/logger' export class LogError extends Error { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/dlt-connector/src/server/createServer.ts b/dlt-connector/src/server/createServer.ts index e02cc3073..ed87d54ac 100755 --- a/dlt-connector/src/server/createServer.ts +++ b/dlt-connector/src/server/createServer.ts @@ -9,10 +9,9 @@ import express, { Express } from 'express' import { Logger } from 'log4js' import { schema } from '@/graphql/schema' +import { logger as dltLogger } from '@/logging/logger' import { Connection } from '@/typeorm/DataSource' -import { logger as dltLogger } from './logger' - type ServerDef = { apollo: ApolloServer; app: Express } interface MyContext { diff --git a/dlt-connector/src/typeorm/DataSource.ts b/dlt-connector/src/typeorm/DataSource.ts index ecdfc1b66..a86a061f3 100644 --- a/dlt-connector/src/typeorm/DataSource.ts +++ b/dlt-connector/src/typeorm/DataSource.ts @@ -5,8 +5,8 @@ import { entities } from '@entity/index' import { Migration } from '@entity/Migration' import { CONFIG } from '@/config' +import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { logger } from '@/server/logger' // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class Connection { diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 1fc46ee4b..52dcd2a98 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -7,8 +7,8 @@ import { TransactionBody } from '@/data/proto/3_3/TransactionBody' import { AccountType } from '@/graphql/enum/AccountType' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionError } from '@/graphql/model/TransactionError' +import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { logger } from '@/server/logger' export const uuid4ToBuffer = (uuid: string): Buffer => { // Remove dashes from the UUIDv4 string diff --git a/dlt-connector/test/testSetup.ts b/dlt-connector/test/testSetup.ts index ff619e95d..1a76560ed 100644 --- a/dlt-connector/test/testSetup.ts +++ b/dlt-connector/test/testSetup.ts @@ -1,4 +1,4 @@ -import { logger } from '@/server/logger' +import { logger } from '@/logging/logger' jest.setTimeout(1000000) From 3ec740e0a5b1ab4893865bc29d7216b084a1afc0 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 16:32:06 +0100 Subject: [PATCH 22/85] fix some bugs --- dlt-connector/jest.config.js | 2 +- .../src/data/proto/3_3/GradidoTransaction.ts | 15 ++++++++++++++ dlt-connector/src/graphql/schema.ts | 1 - .../logging/ConfirmBackendTransaction.view.ts | 20 ------------------- .../src/logging/DecayLogging.view.ts | 20 ------------------- .../logging/TransactionBodyLogging.view.ts | 5 +++-- .../logging/TransactionDraftLogging.view.ts | 4 ++-- dlt-connector/test/testSetup.ts | 4 ++-- 8 files changed, 23 insertions(+), 48 deletions(-) delete mode 100644 dlt-connector/src/logging/ConfirmBackendTransaction.view.ts delete mode 100644 dlt-connector/src/logging/DecayLogging.view.ts diff --git a/dlt-connector/jest.config.js b/dlt-connector/jest.config.js index 2de18cf50..69bc64bb2 100644 --- a/dlt-connector/jest.config.js +++ b/dlt-connector/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 71, + lines: 66, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts b/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts index 4aaa3e25c..f38bcbd1f 100644 --- a/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts +++ b/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts @@ -1,5 +1,8 @@ import { Field, Message } from 'protobufjs' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionError } from '@/graphql/model/TransactionError' +import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' import { SignatureMap } from './SignatureMap' @@ -41,4 +44,16 @@ export class GradidoTransaction extends Message { } return sigPair[0] } + + getTransactionBody(): TransactionBody { + try { + return TransactionBody.decode(new Uint8Array(this.bodyBytes)) + } catch (error) { + logger.error('error decoding body from gradido transaction: %s', error) + throw new TransactionError( + TransactionErrorType.PROTO_DECODE_ERROR, + 'cannot decode body from gradido transaction', + ) + } + } } diff --git a/dlt-connector/src/graphql/schema.ts b/dlt-connector/src/graphql/schema.ts index 19a6d5566..bbd61c63f 100755 --- a/dlt-connector/src/graphql/schema.ts +++ b/dlt-connector/src/graphql/schema.ts @@ -10,7 +10,6 @@ export const schema = async (): Promise => { return buildSchema({ resolvers: [TransactionResolver, CommunityResolver], scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], - emitSchemaFile: true, validate: { validationError: { target: false }, skipMissingProperties: true, diff --git a/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts b/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts deleted file mode 100644 index 667d290dd..000000000 --- a/dlt-connector/src/logging/ConfirmBackendTransaction.view.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ConfirmBackendTransaction } from '@/graphql/model/ConfirmBackendTransaction' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class ConfirmBackendTransactionView extends AbstractLoggingView { - public constructor(private self: ConfirmBackendTransaction) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - transactionId: this.self.transactionId, - iotaMessageId: this.self.iotaMessageId, - gradidoId: this.self.gradidoId, - balance: this.decimalToString(this.self.balance), - balanceDate: this.self.balanceDate, - } - } -} diff --git a/dlt-connector/src/logging/DecayLogging.view.ts b/dlt-connector/src/logging/DecayLogging.view.ts deleted file mode 100644 index cf7817f58..000000000 --- a/dlt-connector/src/logging/DecayLogging.view.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Decay } from '@/graphql/model/Decay' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class DecayLoggingView extends AbstractLoggingView { - public constructor(private self: Decay) { - super() - } - - public toJSON() { - return { - balance: this.decimalToString(this.self.balance), - decay: this.decimalToString(this.self.decay), - roundedDecay: this.decimalToString(this.self.roundedDecay), - start: this.dateToString(this.self.start), - end: this.dateToString(this.self.end), - duration: this.self.duration + 's', - } - } -} diff --git a/dlt-connector/src/logging/TransactionBodyLogging.view.ts b/dlt-connector/src/logging/TransactionBodyLogging.view.ts index 9e08bbfa6..0c287b0a5 100644 --- a/dlt-connector/src/logging/TransactionBodyLogging.view.ts +++ b/dlt-connector/src/logging/TransactionBodyLogging.view.ts @@ -1,5 +1,6 @@ -import { getCrossGroupTypeEnumValue } from '@/data/proto/3_3/enum/CrossGroupType' +import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { TransactionBody } from '@/data/proto/3_3/TransactionBody' +import { getEnumValue } from '@/utils/typeConverter' import { AbstractLoggingView } from './AbstractLogging.view' import { CommunityRootLoggingView } from './CommunityRootLogging.view' @@ -20,7 +21,7 @@ export class TransactionBodyLoggingView extends AbstractLoggingView { memo: this.self.memo, createdAt: this.timestampToDateString(this.self.createdAt), versionNumber: this.self.versionNumber, - type: getCrossGroupTypeEnumValue(this.self.type), + type: getEnumValue(CrossGroupType, this.self.type), otherGroup: this.self.otherGroup, transfer: this.self.transfer ? new GradidoTransferLoggingView(this.self.transfer).toJSON() diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index f2115f591..b3fbbb8ae 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -12,8 +12,8 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { public toJSON() { return { - senderUser: new UserIdentifierLoggingView(this.self.senderUser).toJSON(), - recipientUser: new UserIdentifierLoggingView(this.self.recipientUser).toJSON(), + user: new UserIdentifierLoggingView(this.self.user).toJSON(), + linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), backendTransactionId: this.self.backendTransactionId, amount: this.decimalToString(this.self.amount), type: getEnumValue(InputTransactionType, this.self.type), diff --git a/dlt-connector/test/testSetup.ts b/dlt-connector/test/testSetup.ts index 1a76560ed..71170cbf0 100644 --- a/dlt-connector/test/testSetup.ts +++ b/dlt-connector/test/testSetup.ts @@ -2,8 +2,8 @@ import { logger } from '@/logging/logger' jest.setTimeout(1000000) -jest.mock('@/server/logger', () => { - const originalModule = jest.requireActual('@/server/logger') +jest.mock('@/logging/logger', () => { + const originalModule = jest.requireActual('@/logging/logger') return { __esModule: true, ...originalModule, From 92c0c4a09074e13a81e910b478886261367fe306 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 16:41:45 +0100 Subject: [PATCH 23/85] make more similar --- dlt-connector/src/logging/AbstractLogging.view.ts | 8 ++++---- dlt-connector/src/logging/AccountLogging.view.ts | 3 +-- dlt-connector/src/logging/SignatureMapLogging.view.ts | 3 ++- dlt-connector/src/logging/SignaturePairLogging.view.ts | 3 ++- dlt-connector/src/logging/TransactionDraftLogging.view.ts | 3 ++- dlt-connector/src/logging/UserIdentifierLogging.view.ts | 3 ++- dlt-connector/src/logging/UserLogging.view.ts | 3 ++- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/dlt-connector/src/logging/AbstractLogging.view.ts b/dlt-connector/src/logging/AbstractLogging.view.ts index 3d9c2f811..ad52e6530 100644 --- a/dlt-connector/src/logging/AbstractLogging.view.ts +++ b/dlt-connector/src/logging/AbstractLogging.view.ts @@ -21,27 +21,27 @@ export abstract class AbstractLoggingView { return this.toString() } - public dateToString(date: Date | undefined | null): string | undefined { + protected dateToString(date: Date | undefined | null): string | undefined { if (date) { return date.toISOString() } return undefined } - public decimalToString(number: Decimal | undefined | null): string | undefined { + protected decimalToString(number: Decimal | undefined | null): string | undefined { if (number) { return number.toString() } return undefined } - public timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { + protected timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { if (timestamp && timestamp.seconds) { return timestampSecondsToDate(timestamp).toISOString() } } - public timestampToDateString(timestamp: Timestamp): string | undefined { + protected timestampToDateString(timestamp: Timestamp): string | undefined { if (timestamp && (timestamp.seconds || timestamp.nanoSeconds)) { return timestampToDate(timestamp).toISOString() } diff --git a/dlt-connector/src/logging/AccountLogging.view.ts b/dlt-connector/src/logging/AccountLogging.view.ts index e4f00e272..76ff7b891 100644 --- a/dlt-connector/src/logging/AccountLogging.view.ts +++ b/dlt-connector/src/logging/AccountLogging.view.ts @@ -11,8 +11,7 @@ export class AccountLoggingView extends AbstractLoggingView { super() } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { + public toJSON() { return { id: this.account.id, user: this.account.user ? new UserLoggingView(this.account.user).toJSON() : null, diff --git a/dlt-connector/src/logging/SignatureMapLogging.view.ts b/dlt-connector/src/logging/SignatureMapLogging.view.ts index 89c331a64..93feb46f9 100644 --- a/dlt-connector/src/logging/SignatureMapLogging.view.ts +++ b/dlt-connector/src/logging/SignatureMapLogging.view.ts @@ -8,7 +8,8 @@ export class SignatureMapLoggingView extends AbstractLoggingView { super() } - public toJSON() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { return { sigPair: this.self.sigPair.map((value) => new SignaturePairLoggingView(value).toJSON()), } diff --git a/dlt-connector/src/logging/SignaturePairLogging.view.ts b/dlt-connector/src/logging/SignaturePairLogging.view.ts index c3317a5ec..e88406098 100644 --- a/dlt-connector/src/logging/SignaturePairLogging.view.ts +++ b/dlt-connector/src/logging/SignaturePairLogging.view.ts @@ -7,7 +7,8 @@ export class SignaturePairLoggingView extends AbstractLoggingView { super() } - public toJSON() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { return { pubkey: Buffer.from(this.self.pubKey).toString(this.bufferStringFormat), signature: diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index b3fbbb8ae..5e86822ec 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -10,7 +10,8 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { super() } - public toJSON() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { return { user: new UserIdentifierLoggingView(this.self.user).toJSON(), linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), diff --git a/dlt-connector/src/logging/UserIdentifierLogging.view.ts b/dlt-connector/src/logging/UserIdentifierLogging.view.ts index b49fb604c..54ac4b07d 100644 --- a/dlt-connector/src/logging/UserIdentifierLogging.view.ts +++ b/dlt-connector/src/logging/UserIdentifierLogging.view.ts @@ -7,7 +7,8 @@ export class UserIdentifierLoggingView extends AbstractLoggingView { super() } - public toJSON() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { return { uuid: this.self.uuid, communityUuid: this.self.communityUuid, diff --git a/dlt-connector/src/logging/UserLogging.view.ts b/dlt-connector/src/logging/UserLogging.view.ts index 4db4f61fd..a3cbd66bc 100644 --- a/dlt-connector/src/logging/UserLogging.view.ts +++ b/dlt-connector/src/logging/UserLogging.view.ts @@ -7,7 +7,8 @@ export class UserLoggingView extends AbstractLoggingView { super() } - public toJSON() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { return { id: this.user.id, gradidoId: this.user.gradidoID, From dc8c4b0f845efca65b5721c925fc92a8a3e74d18 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 9 Jan 2024 16:43:36 +0100 Subject: [PATCH 24/85] lint fix --- dlt-connector/src/graphql/resolver/TransactionsResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index cc20a1034..6a5017fb1 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,6 +1,7 @@ -import { TransactionDraft } from '@input/TransactionDraft' import { Resolver, Arg, Mutation } from 'type-graphql' +import { TransactionDraft } from '@input/TransactionDraft' + import { TransactionRepository } from '@/data/Transaction.repository' import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransationRecipe.context' import { BackendTransactionLoggingView } from '@/logging/BackendTransactionLogging.view' From f5fbdb7ec6aa8ffb4abb64541792715ec96cc546 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 10 Jan 2024 21:30:01 +0100 Subject: [PATCH 25/85] split install script in root and gradido parts --- .../sites-available/gradido.conf.ssl.template | 6 +-- .../update-page.conf.ssl.template | 6 +-- deployment/hetzner_cloud/install.sh | 51 +++---------------- deployment/hetzner_cloud/install_gradido.sh | 48 +++++++++++++++++ 4 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 deployment/hetzner_cloud/install_gradido.sh diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index a99327745..b8559a0fb 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -1,16 +1,16 @@ server { - if ($host = $NGINX_SERVER_NAME) { + if ($host = $COMMUNITY_HOST) { return 301 https://$host$request_uri; } - server_name $NGINX_SERVER_NAME; + server_name $COMMUNITY_HOST; listen 80; listen [::]:80; return 404; } server { - server_name $NGINX_SERVER_NAME; + server_name $COMMUNITY_HOST; listen [::]:443 ssl ipv6only=on; listen 443 ssl; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template index ddcb9ffc1..06bc5bbc0 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -1,16 +1,16 @@ server { - if ($host = $NGINX_SERVER_NAME) { + if ($host = $COMMUNITY_HOST) { return 301 https://$host$request_uri; } - server_name $NGINX_SERVER_NAME; + server_name $COMMUNITY_HOST; listen 80; listen [::]:80; return 404; } server { - server_name $NGINX_SERVER_NAME; + server_name $COMMUNITY_HOST; listen [::]:443 ssl ipv6only=on; listen 443 ssl; diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index ae1c106ca..8a2d18a16 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -80,12 +80,15 @@ expect eof ") echo "$SECURE_MYSQL" +# create db user +export DB_USER=gradido +export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); + +# run all commands which must be called in gradido user space +sudo -u gradido $LOCAL_SCRIPT_DIR/install_gradido.sh + # Configure nginx rm /etc/nginx/sites-enabled/default -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf -sudo -u gradido mkdir $SCRIPT_PATH/nginx/sites-enabled -ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default ln -s $SCRIPT_PATH/nginx/sites-enabled/default /etc/nginx/sites-enabled ln -s $SCRIPT_PATH/nginx/common /etc/nginx/ rmdir /etc/nginx/conf.d @@ -94,54 +97,16 @@ ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ # setup https with certbot certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL -# Install node 16. with nvm, with nodesource is depracted -sudo -u gradido bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash' -# Close and reopen your terminal to start using nvm or run the following to use it now: -sudo -u gradido bash -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' -sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && nvm install 16' # first installed version will be set to default automatic - -# Install yarn -sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g yarn' - -# Install pm2 -sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g pm2 && pm2 startup' - # Install logrotate -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf -# create db user -export DB_USER=gradido -export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +# setup db user mysql < $PROJECT_ROOT/database/.env - -# Configure backend -export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); -sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env - -# Configure frontend -sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env - -# Configure admin -sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env - -# Configure dht-node -export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); -sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env - -# Configure federation -sudo -u gradido envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env - -# create cronjob to delete yarn output in /tmp and for making backups regulary -sudo -u gradido crontab < $LOCAL_SCRIPT_DIR/crontabs.txt - # Start gradido # Note: on first startup some errors will occur - nothing serious sudo -u gradido $SCRIPT_PATH/start.sh \ No newline at end of file diff --git a/deployment/hetzner_cloud/install_gradido.sh b/deployment/hetzner_cloud/install_gradido.sh new file mode 100644 index 000000000..b2db53cf3 --- /dev/null +++ b/deployment/hetzner_cloud/install_gradido.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# called from install.sh as gradido user +# ENV variables from install.sh are accessable by child scripts +# changing don't count for calling script + +# Configure nginx +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf +mkdir $SCRIPT_PATH/nginx/sites-enabled +ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default + +# Install node 16. with nvm, with nodesource is depracted +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash +# Close and reopen your terminal to start using nvm or run the following to use it now: +export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +nvm install 16 # first installed version will be set to default automatic + +# Install yarn +npm i -g yarn + +# Install pm2 +npm i -g pm2 && pm2 startup + +# Install logrotate +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf + +# Configure database +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env + +# Configure backend +export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env + +# Configure frontend +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env + +# Configure admin +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env + +# Configure dht-node +export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env + +# Configure federation +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env + +# create cronjob to delete yarn output in /tmp and for making backups regulary +crontab < $LOCAL_SCRIPT_DIR/crontabs.txt From abc4843a0e2168ca1ef4631b4365fa696697b74d Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 10 Jan 2024 21:56:12 +0100 Subject: [PATCH 26/85] make install_gradido executable --- deployment/hetzner_cloud/install_gradido.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 deployment/hetzner_cloud/install_gradido.sh diff --git a/deployment/hetzner_cloud/install_gradido.sh b/deployment/hetzner_cloud/install_gradido.sh old mode 100644 new mode 100755 From e58ec8ad346cecd83870d6e1785d559253007f75 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 10 Jan 2024 22:21:42 +0100 Subject: [PATCH 27/85] use chown after --- backend/.env.template | 2 +- deployment/bare_metal/.env.dist | 12 ++++- deployment/hetzner_cloud/install.sh | 56 +++++++++++++++++---- deployment/hetzner_cloud/install_gradido.sh | 48 ------------------ 4 files changed, 58 insertions(+), 60 deletions(-) delete mode 100755 deployment/hetzner_cloud/install_gradido.sh diff --git a/backend/.env.template b/backend/.env.template index 9133428ab..9adb09793 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -49,7 +49,7 @@ EMAIL_USERNAME=$EMAIL_USERNAME EMAIL_SENDER=$EMAIL_SENDER EMAIL_PASSWORD=$EMAIL_PASSWORD EMAIL_SMTP_URL=$EMAIL_SMTP_URL -EMAIL_SMTP_PORT=587 +EMAIL_SMTP_PORT=$EMAIL_SMTP_PORT EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 326392124..ebdc9f277 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -6,13 +6,17 @@ COMMUNITY_SUPPORT_MAIL=support@supportmail.com # setup email account for sending gradido system messages to users EMAIL=true -EMAIL_TEST_MODUS=false -EMAIL_TEST_RECEIVER=test_team@gradido.net EMAIL_USERNAME=peter@lustig.de EMAIL_SENDER=peter@lustig.de EMAIL_PASSWORD=1234 EMAIL_SMTP_URL=smtp.lustig.de +EMAIL_SMTP_PORT=587 + +# how many minutes email verification code is valid +# also used for password reset code EMAIL_CODE_VALID_TIME=1440 +# how many minutes user must wait before he can request the email verification code again +# also used for password reset code EMAIL_CODE_REQUEST_TIME=10 # Need to adjust by updates @@ -31,6 +35,10 @@ URL_PROTOCOL=https # start script # only for test server DEPLOY_SEED_DATA=false +# test email +# if true all email will be send to EMAIL_TEST_RECEIVER instead of email address of user +EMAIL_TEST_MODUS=false +EMAIL_TEST_RECEIVER=test_team@gradido.net # Logging GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index 8a2d18a16..b83cdae68 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -10,7 +10,7 @@ set -o allexport SCRIPT_PATH=$(realpath ../bare_metal) SCRIPT_DIR=$(dirname $SCRIPT_PATH) LOCAL_SCRIPT_PATH=$(realpath $0) -LOCAL_SCRIPT_DIR=$(dirname $SCRIPT_PATH) +LOCAL_SCRIPT_DIR=$(dirname $LOCAL_SCRIPT_PATH) PROJECT_ROOT=$SCRIPT_DIR/.. set +o allexport @@ -80,15 +80,12 @@ expect eof ") echo "$SECURE_MYSQL" -# create db user -export DB_USER=gradido -export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); - -# run all commands which must be called in gradido user space -sudo -u gradido $LOCAL_SCRIPT_DIR/install_gradido.sh - # Configure nginx rm /etc/nginx/sites-enabled/default +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf +mkdir $SCRIPT_PATH/nginx/sites-enabled +ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default ln -s $SCRIPT_PATH/nginx/sites-enabled/default /etc/nginx/sites-enabled ln -s $SCRIPT_PATH/nginx/common /etc/nginx/ rmdir /etc/nginx/conf.d @@ -97,16 +94,57 @@ ln -s $SCRIPT_PATH/nginx/conf.d /etc/nginx/ # setup https with certbot certbot certonly --nginx --non-interactive --agree-tos --domains $COMMUNITY_HOST --email $COMMUNITY_SUPPORT_MAIL +# Install node 16. with nvm, with nodesource is depracted +sudo -u gradido bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash' +# Close and reopen your terminal to start using nvm or run the following to use it now: +sudo -u gradido bash -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && nvm install 16' # first installed version will be set to default automatic + +# Install yarn +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g yarn' + +# Install pm2 +sudo -u gradido bash -c '. $HOME/.nvm/nvm.sh && npm i -g pm2 && pm2 startup' + # Install logrotate +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf -# setup db user +# create db user +export DB_USER=gradido +export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); mysql < $PROJECT_ROOT/database/.env + +# Configure backend +export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env + +# Configure frontend +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env + +# Configure admin +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env + +# Configure dht-node +export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env + +# Configure federation +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env + +# set all created or modified files back to belonging to gradido +chown -R gradido:gradido $PROJECT_ROOT + +# create cronjob to delete yarn output in /tmp and for making backups regulary +sudo -u gradido crontab < $LOCAL_SCRIPT_DIR/crontabs.txt + # Start gradido # Note: on first startup some errors will occur - nothing serious sudo -u gradido $SCRIPT_PATH/start.sh \ No newline at end of file diff --git a/deployment/hetzner_cloud/install_gradido.sh b/deployment/hetzner_cloud/install_gradido.sh deleted file mode 100755 index b2db53cf3..000000000 --- a/deployment/hetzner_cloud/install_gradido.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# called from install.sh as gradido user -# ENV variables from install.sh are accessable by child scripts -# changing don't count for calling script - -# Configure nginx -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/update-page.conf.template > $SCRIPT_PATH/nginx/sites-available/update-page.conf -mkdir $SCRIPT_PATH/nginx/sites-enabled -ln -s $SCRIPT_PATH/nginx/sites-available/update-page.conf $SCRIPT_PATH/nginx/sites-enabled/default - -# Install node 16. with nvm, with nodesource is depracted -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash -# Close and reopen your terminal to start using nvm or run the following to use it now: -export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" -nvm install 16 # first installed version will be set to default automatic - -# Install yarn -npm i -g yarn - -# Install pm2 -npm i -g pm2 && pm2 startup - -# Install logrotate -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/logrotate/gradido.conf.template > $SCRIPT_PATH/logrotate/gradido.conf - -# Configure database -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env - -# Configure backend -export JWT_SECRET=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env - -# Configure frontend -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env - -# Configure admin -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env - -# Configure dht-node -export FEDERATION_DHT_SEED=$(< /dev/urandom tr -dc a-f0-9 | head -c 32;echo); -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env - -# Configure federation -envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/federation/.env.template > $PROJECT_ROOT/federation/.env - -# create cronjob to delete yarn output in /tmp and for making backups regulary -crontab < $LOCAL_SCRIPT_DIR/crontabs.txt From 1494a9ae1e15d32b03f51465da4c85d7f8f86f24 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 10 Jan 2024 23:05:58 +0100 Subject: [PATCH 28/85] export env, move starting modules after building all modules --- deployment/bare_metal/start.sh | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index b68d5aea8..4b6498ee0 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -48,6 +48,10 @@ fi : ${NGINX_SSL_CERTIFICATE:=/etc/letsencrypt/live/$COMMUNITY_HOST/fullchain.pem} : ${NGINX_SSL_CERTIFICATE_KEY:=/etc/letsencrypt/live/$COMMUNITY_HOST/privkey.pem} +# export env variables +export NGINX_SSL_CERTIFICATE +export NGINX_SSL_CERTIFICATE_KEY + # lock start if [ -f $LOCK_FILE ] ; then echo "Already building!" @@ -189,8 +193,7 @@ if [ "$DEPLOY_SEED_DATA" = "true" ]; then fi # TODO maybe handle this differently? export NODE_ENV=production -pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' -pm2 save + # Install & build frontend echo 'Updating frontend' >> $UPDATE_HTML @@ -201,8 +204,6 @@ yarn install yarn build # TODO maybe handle this differently? export NODE_ENV=production -pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' -pm2 save # Install & build admin echo 'Updating admin' >> $UPDATE_HTML @@ -213,8 +214,6 @@ yarn install yarn build # TODO maybe handle this differently? export NODE_ENV=production -pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' -pm2 save # Install & build dht-node echo 'Updating dht-node' >> $UPDATE_HTML @@ -225,15 +224,6 @@ yarn install yarn build # TODO maybe handle this differently? export NODE_ENV=production -if [ ! -z $FEDERATION_DHT_TOPIC ]; then - pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' - pm2 save -else - echo "=====================================================================" >> $UPDATE_HTML - echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." >> $UPDATE_HTML - echo "=====================================================================" >> $UPDATE_HTML -fi - # Install & build federation echo 'Updating federation' >> $UPDATE_HTML @@ -245,6 +235,20 @@ yarn build # TODO maybe handle this differently? export NODE_ENV=production +# start after building all to use up less ressources +pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +pm2 save +if [ ! -z $FEDERATION_DHT_TOPIC ]; then + pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' + pm2 save +else + echo "=====================================================================" >> $UPDATE_HTML + echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." >> $UPDATE_HTML + echo "=====================================================================" >> $UPDATE_HTML +fi + # set FEDERATION_PORT from FEDERATION_COMMUNITY_APIS IFS="," read -a API_ARRAY <<< $FEDERATION_COMMUNITY_APIS for api in "${API_ARRAY[@]}" @@ -266,9 +270,6 @@ do pm2 save done - - - # let nginx showing gradido echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML ln -sf $SCRIPT_DIR/nginx/sites-available/gradido.conf $SCRIPT_DIR/nginx/sites-enabled/default From 6fe8eead938217ab20c842f0ff1fa185358486fb Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 10 Jan 2024 23:20:48 +0100 Subject: [PATCH 29/85] fix minor --- backend/.env.template | 2 +- frontend/.env.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/.env.template b/backend/.env.template index 9adb09793..d279ba705 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,5 +1,5 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=v20.2023-09-19 +CONFIG_VERSION=$BACKEND_CONFIG_VERSION # Server JWT_SECRET=$JWT_SECRET diff --git a/frontend/.env.template b/frontend/.env.template index e5662140c..c365ab8cf 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -16,7 +16,7 @@ COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION COMMUNITY_SUPPORT_MAIL=$COMMUNITY_SUPPORT_MAIL # Meta -META_URL=$META_URL +META_URL=$COMMUNITY_HOST META_TITLE_DE=$META_TITLE_DE META_TITLE_EN=$META_TITLE_EN META_DESCRIPTION_DE=$META_DESCRIPTION_DE From 90408664f619d86119506b6037f87d103d3502f7 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 11 Jan 2024 13:15:48 +0100 Subject: [PATCH 30/85] fix missing/wrong config --- backend/.env.template | 10 +++++----- deployment/bare_metal/.env.dist | 8 +++++++- deployment/hetzner_cloud/README.md | 8 +++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/backend/.env.template b/backend/.env.template index d279ba705..1cf7d9dee 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -50,11 +50,11 @@ EMAIL_SENDER=$EMAIL_SENDER EMAIL_PASSWORD=$EMAIL_PASSWORD EMAIL_SMTP_URL=$EMAIL_SMTP_URL EMAIL_SMTP_PORT=$EMAIL_SMTP_PORT -EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION -EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD -EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD -EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW -EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME +EMAIL_LINK_VERIFICATION_PATH=$EMAIL_LINK_VERIFICATION_PATH +EMAIL_LINK_SETPASSWORD_PATH=$EMAIL_LINK_SETPASSWORD_PATH +EMAIL_LINK_FORGOTPASSWORD_PATH=$EMAIL_LINK_FORGOTPASSWORD_PATH +EMAIL_LINK_OVERVIEW_PATH=$EMAIL_LINK_OVERVIEW_PATH +EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME_PATH EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME # Webhook diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index ebdc9f277..83fe34968 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -41,8 +41,9 @@ EMAIL_TEST_MODUS=false EMAIL_TEST_RECEIVER=test_team@gradido.net # Logging +LOG_LEVEL=WARN GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log -TYPEORM_LOGGING_RELATIVE_PATH=/home/gradido/gradido/deployment/bare_metal/log/typeorm.backend.log +TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log # webhook WEBHOOK_GITHUB_SECRET=secret @@ -72,6 +73,7 @@ JWT_EXPIRES_IN=10m # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f # the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010 FEDERATION_COMMUNITY_API_PORT=5000 +FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 # comma separated list of api-versions, which cause starting several federation modules FEDERATION_COMMUNITY_APIS=1_0,1_1 @@ -79,6 +81,10 @@ FEDERATION_COMMUNITY_APIS=1_0,1_1 # externe gradido services (more added in future) GDT_API_URL=https://gdt.gradido.net +# DLT-Connector (still in develop) +DLT_CONNECTOR=false +DLT_CONNECTOR_PORT=6010 + # used for combining a newsletter on klicktipp with this gradido community # if used, user will be subscribed on register and can unsubscribe in his account KLICKTIPP=false diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md index 5a5ae3186..d7f7cf13a 100644 --- a/deployment/hetzner_cloud/README.md +++ b/deployment/hetzner_cloud/README.md @@ -106,4 +106,10 @@ will remove it and ln ../bare_metal/nginx/conf.d ```bash cd ~/gradido/deployment/hetzner_cloud -sudo ./install.sh \ No newline at end of file +sudo ./install.sh + +### Make yourself admin + +```mysql +insert into user_roles(user_id, role) values(276, 'ADMIN'); +``` \ No newline at end of file From b40dbf561e70b2c336cd356f31cbe269492948c3 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 11 Jan 2024 14:02:23 +0100 Subject: [PATCH 31/85] info log level --- deployment/bare_metal/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 83fe34968..eb1e45f79 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -41,7 +41,7 @@ EMAIL_TEST_MODUS=false EMAIL_TEST_RECEIVER=test_team@gradido.net # Logging -LOG_LEVEL=WARN +LOG_LEVEL=INFO GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log From 31283c509435996a9656011916168719beeddac9 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 11 Jan 2024 14:53:03 +0100 Subject: [PATCH 32/85] move call for validate federation --- backend/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index 86f78326d..4961e880d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,6 +5,8 @@ import { createServer } from './server/createServer' async function main() { const { app } = await createServer() + void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) + // app listen don't return as long as the express server is running app.listen(CONFIG.PORT, () => { // eslint-disable-next-line no-console console.log(`Server is running at http://localhost:${CONFIG.PORT}`) @@ -13,7 +15,6 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) } }) - void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } main().catch((e) => { From 0982e4fa4fc0dd6d039f6206f1c7dff0243768d6 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 11 Jan 2024 15:08:12 +0100 Subject: [PATCH 33/85] never mind --- backend/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index 4961e880d..86f78326d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -5,8 +5,6 @@ import { createServer } from './server/createServer' async function main() { const { app } = await createServer() - void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) - // app listen don't return as long as the express server is running app.listen(CONFIG.PORT, () => { // eslint-disable-next-line no-console console.log(`Server is running at http://localhost:${CONFIG.PORT}`) @@ -15,6 +13,7 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) } }) + void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } main().catch((e) => { From 073edb57b575e53a1fff65b61fb864ddf361d5b2 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 17 Jan 2024 13:30:31 +0100 Subject: [PATCH 34/85] add logging view class for community and use it in dht-node --- database/logging/AbstractLogging.view.ts | 33 +++++++++++++++++++++++ database/logging/CommunityLogging.view.ts | 26 ++++++++++++++++++ dht-node/src/dht_node/index.ts | 5 ++-- dht-node/tsconfig.json | 3 ++- 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 database/logging/AbstractLogging.view.ts create mode 100644 database/logging/CommunityLogging.view.ts diff --git a/database/logging/AbstractLogging.view.ts b/database/logging/AbstractLogging.view.ts new file mode 100644 index 000000000..a30254b86 --- /dev/null +++ b/database/logging/AbstractLogging.view.ts @@ -0,0 +1,33 @@ +import util from 'util' + +import { Decimal } from 'decimal.js-light' + +export abstract class AbstractLoggingView { + protected bufferStringFormat: BufferEncoding = 'hex' + + // This function gets called automatically when JSON.stringify() is called on this class instance + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public abstract toJSON(): any + public toString(): string { + return JSON.stringify(this.toJSON(), null, 2) + } + + // called form console.log or log4js logging functions + [util.inspect.custom](): string { + return this.toString() + } + + public dateToString(date: Date | undefined | null): string | undefined { + if (date) { + return date.toISOString() + } + return undefined + } + + public decimalToString(number: Decimal | undefined | null): string | undefined { + if (number) { + return number.toString() + } + return undefined + } +} diff --git a/database/logging/CommunityLogging.view.ts b/database/logging/CommunityLogging.view.ts new file mode 100644 index 000000000..1c6d74626 --- /dev/null +++ b/database/logging/CommunityLogging.view.ts @@ -0,0 +1,26 @@ +import { Community } from '../entity/Community' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class CommunityLoggingView extends AbstractLoggingView { + public constructor(private self: Community) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + url: this.self.url, + publicKey: this.self.publicKey.toString(this.bufferStringFormat), + communityUuid: this.self.communityUuid, + authenticatedAt: this.dateToString(this.self.authenticatedAt), + name: this.self.name, + description: this.self.description?.substring(0, 24), + creationDate: this.dateToString(this.self.creationDate), + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index c9fad8762..536966591 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -3,6 +3,7 @@ import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import DHT from '@hyperswarm/dht' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' @@ -227,7 +228,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION await DbCommunity.save(homeCom) - logger.info(`home-community updated successfully:`, homeCom) + logger.info(`home-community updated successfully:`, new CommunityLoggingView(homeCom)) } else { // insert a new homecommunity entry including a new ID and a new but ensured unique UUID homeCom = new DbCommunity() @@ -240,7 +241,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { homeCom.description = CONFIG.COMMUNITY_DESCRIPTION homeCom.creationDate = new Date() await DbCommunity.insert(homeCom) - logger.info(`home-community inserted successfully:`, homeCom) + logger.info(`home-community inserted successfully:`, new CommunityLoggingView(homeCom)) } } catch (err) { throw new Error(`Federation: Error writing HomeCommunity-Entry: ${err}`) diff --git a/dht-node/tsconfig.json b/dht-node/tsconfig.json index 2c6104021..33362b054 100644 --- a/dht-node/tsconfig.json +++ b/dht-node/tsconfig.json @@ -52,7 +52,8 @@ /* external */ "@typeorm/*": ["../backend/src/typeorm/*", "../../backend/src/typeorm/*"], "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["src/dht_node/@types", "node_modules/@types"], /* List of folders to include type definitions from. */ From f182c5466ae33743b7c6eb16cebb5f96b60a4bc5 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 17 Jan 2024 14:34:07 +0100 Subject: [PATCH 35/85] create mysql user and password only of not already exist --- deployment/hetzner_cloud/install.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index b83cdae68..ee539370c 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -112,9 +112,12 @@ cp $SCRIPT_PATH/logrotate/gradido.conf /etc/logrotate.d/gradido.conf # create db user export DB_USER=gradido -export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +# create a new password only if it not already exist +if [ -z "${DB_PASSWORD}" ]; then + export DB_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo); +fi mysql < Date: Wed, 17 Jan 2024 15:29:40 +0100 Subject: [PATCH 36/85] update readmeg --- deployment/hetzner_cloud/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/deployment/hetzner_cloud/README.md b/deployment/hetzner_cloud/README.md index d7f7cf13a..d03ff0b46 100644 --- a/deployment/hetzner_cloud/README.md +++ b/deployment/hetzner_cloud/README.md @@ -107,9 +107,18 @@ will remove it and ln ../bare_metal/nginx/conf.d ```bash cd ~/gradido/deployment/hetzner_cloud sudo ./install.sh +``` ### Make yourself admin +- Create an account on your new gradido instance +- Click the link in the activation email +- go back to your ssh session and copy this command + +```bash +sudo mysql -D gradido_community -e "insert into user_roles(user_id, role) values((select id from users order by id desc limit 1), 'ADMIN');" +``` + +- it will make last registered user admin +- login with you newly created user +- if you has a link to `Admin Area` it worked and you are admin -```mysql -insert into user_roles(user_id, role) values(276, 'ADMIN'); -``` \ No newline at end of file From 17a067e99b57b4fe9f69f95e812ed3cb987b2394 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 13:10:58 +0100 Subject: [PATCH 37/85] add and use logging view class, annonce only configured api version --- .../client/1_0/AuthenticationClient.ts | 6 +- .../federation/client/1_0/FederationClient.ts | 26 +++--- .../federation/client/1_0/SendCoinsClient.ts | 72 ++++++++++------- .../PublicCommunityInfoLogging.view.ts | 19 +++++ .../1_0/logging/SendCoinsArgsLogging.view.ts | 24 ++++++ .../logging/SendCoinsResultLogging.view.ts | 20 +++++ .../client/1_0/model/GetPublicKeyResult.ts | 13 +++ backend/src/federation/validateCommunities.ts | 16 ++-- backend/tsconfig.json | 3 +- database/logging/AbstractLogging.view.ts | 9 ++- .../logging/FederatedCommunityLogging.view.ts | 24 ++++++ dht-node/.env.dist | 4 +- dht-node/.env.template | 3 +- dht-node/src/config/index.ts | 4 +- dht-node/src/dht_node/index.ts | 10 ++- ...etPublicCommunityInfoResultLogging.view.ts | 18 +++++ .../1_0/logger/SendCoinsArgsLogging.view.ts | 23 ++++++ .../1_0/model/GetPublicCommunityInfoResult.ts | 2 +- .../1_0/resolver/AuthenticationResolver.ts | 17 ++-- .../resolver/PublicCommunityInfoResolver.ts | 7 +- .../api/1_0/resolver/PublicKeyResolver.ts | 6 +- .../api/1_0/resolver/SendCoinsResolver.ts | 81 +++++-------------- .../api/1_0/util/authenticateCommunity.ts | 22 ++++- federation/tsconfig.json | 3 +- 24 files changed, 292 insertions(+), 140 deletions(-) create mode 100644 backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts create mode 100644 backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts create mode 100644 backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts create mode 100644 backend/src/federation/client/1_0/model/GetPublicKeyResult.ts create mode 100644 database/logging/FederatedCommunityLogging.view.ts create mode 100644 federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts create mode 100644 federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts diff --git a/backend/src/federation/client/1_0/AuthenticationClient.ts b/backend/src/federation/client/1_0/AuthenticationClient.ts index abc903778..f73393255 100644 --- a/backend/src/federation/client/1_0/AuthenticationClient.ts +++ b/backend/src/federation/client/1_0/AuthenticationClient.ts @@ -28,9 +28,9 @@ export class AuthenticationClient { async openConnection(args: OpenConnectionArgs): Promise { logger.debug(`Authentication: openConnection at ${this.endpoint} for args:`, args) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(openConnection, { args }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ openConnection: boolean }>(openConnection, { + args, + }) if (!data?.openConnection) { logger.warn( 'Authentication: openConnection without response data from endpoint', diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 8d915c751..4a10ddc7e 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -5,9 +5,10 @@ import { getPublicCommunityInfo } from '@/federation/client/1_0/query/getPublicC import { getPublicKey } from '@/federation/client/1_0/query/getPublicKey' import { backendLogger as logger } from '@/server/logger' +import { PublicCommunityInfoLoggingView } from './logging/PublicCommunityInfoLogging.view' +import { GetPublicKeyResult } from './model/GetPublicKeyResult' import { PublicCommunityInfo } from './model/PublicCommunityInfo' -// eslint-disable-next-line camelcase export class FederationClient { dbCom: DbFederatedCommunity endpoint: string @@ -30,9 +31,10 @@ export class FederationClient { getPublicKey = async (): Promise => { logger.debug('Federation: getPublicKey from endpoint', this.endpoint) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(getPublicKey, {}) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ getPublicKey: GetPublicKeyResult }>( + getPublicKey, + {}, + ) if (!data?.getPublicKey?.publicKey) { logger.warn('Federation: getPublicKey without response data from endpoint', this.endpoint) return @@ -40,10 +42,8 @@ export class FederationClient { logger.debug( 'Federation: getPublicKey successful from endpoint', this.endpoint, - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access data.getPublicKey.publicKey, ) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access return data.getPublicKey.publicKey } catch (err) { logger.warn('Federation: getPublicKey failed for endpoint', this.endpoint) @@ -53,9 +53,10 @@ export class FederationClient { getPublicCommunityInfo = async (): Promise => { logger.debug(`Federation: getPublicCommunityInfo with endpoint='${this.endpoint}'...`) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(getPublicCommunityInfo, {}) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ + getPublicCommunityInfo: PublicCommunityInfo + }>(getPublicCommunityInfo, {}) + if (!data?.getPublicCommunityInfo?.name) { logger.warn( 'Federation: getPublicCommunityInfo without response data from endpoint', @@ -64,9 +65,10 @@ export class FederationClient { return } logger.debug(`Federation: getPublicCommunityInfo successful from endpoint=${this.endpoint}`) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - logger.debug(`publicCommunityInfo:`, data.getPublicCommunityInfo) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + logger.debug( + `publicCommunityInfo:`, + new PublicCommunityInfoLoggingView(data.getPublicCommunityInfo), + ) return data.getPublicCommunityInfo } catch (err) { logger.warn('Federation: getPublicCommunityInfo failed for endpoint', this.endpoint) diff --git a/backend/src/federation/client/1_0/SendCoinsClient.ts b/backend/src/federation/client/1_0/SendCoinsClient.ts index c96961103..bcf303584 100644 --- a/backend/src/federation/client/1_0/SendCoinsClient.ts +++ b/backend/src/federation/client/1_0/SendCoinsClient.ts @@ -4,6 +4,8 @@ import { GraphQLClient } from 'graphql-request' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' +import { SendCoinsArgsLoggingView } from './logging/SendCoinsArgsLogging.view' +import { SendCoinsResultLoggingView } from './logging/SendCoinsResultLogging.view' import { SendCoinsArgs } from './model/SendCoinsArgs' import { SendCoinsResult } from './model/SendCoinsResult' import { revertSendCoins as revertSendCoinsQuery } from './query/revertSendCoins' @@ -11,7 +13,6 @@ import { revertSettledSendCoins as revertSettledSendCoinsQuery } from './query/r import { settleSendCoins as settleSendCoinsQuery } from './query/settleSendCoins' import { voteForSendCoins as voteForSendCoinsQuery } from './query/voteForSendCoins' -// eslint-disable-next-line camelcase export class SendCoinsClient { dbCom: DbFederatedCommunity endpoint: string @@ -34,26 +35,26 @@ export class SendCoinsClient { async voteForSendCoins(args: SendCoinsArgs): Promise { logger.debug('X-Com: voteForSendCoins against endpoint=', this.endpoint) try { - logger.debug(`X-Com: SendCoinsClient: voteForSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(voteForSendCoinsQuery, { args }) - logger.debug(`X-Com: SendCoinsClient: after rawRequest...data:`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + logger.debug( + `X-Com: SendCoinsClient: voteForSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ voteForSendCoins: SendCoinsResult }>( + voteForSendCoinsQuery, + { args }, + ) + const result = data.voteForSendCoins if (!data?.voteForSendCoins?.vote) { - logger.debug('X-Com: voteForSendCoins failed with: ', data) + logger.debug( + 'X-Com: voteForSendCoins failed with: ', + new SendCoinsResultLoggingView(result), + ) return new SendCoinsResult() } - const result = new SendCoinsResult() - result.vote = true - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipGradidoID = data.voteForSendCoins.recipGradidoID - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipFirstName = data.voteForSendCoins.recipFirstName - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipLastName = data.voteForSendCoins.recipLastName - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipAlias = data.voteForSendCoins.recipAlias - logger.debug('X-Com: voteForSendCoins successful with result=', result) + logger.debug( + 'X-Com: voteForSendCoins successful with result=', + new SendCoinsResultLoggingView(result), + ) return result } catch (err) { throw new LogError(`X-Com: voteForSendCoins failed for endpoint=${this.endpoint}:`, err) @@ -63,11 +64,15 @@ export class SendCoinsClient { async revertSendCoins(args: SendCoinsArgs): Promise { logger.debug('X-Com: revertSendCoins against endpoint=', this.endpoint) try { - logger.debug(`X-Com: SendCoinsClient: revertSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(revertSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: revertSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ revertSendCoins: boolean }>( + revertSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after revertSendCoins: data=`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.revertSendCoins) { logger.warn('X-Com: revertSendCoins without response data from endpoint', this.endpoint) return false @@ -88,11 +93,15 @@ export class SendCoinsClient { async settleSendCoins(args: SendCoinsArgs): Promise { logger.debug(`X-Com: settleSendCoins against endpoint='${this.endpoint}'...`) try { - logger.debug(`X-Com: SendCoinsClient: settleSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(settleSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: settleSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ settleSendCoins: boolean }>( + settleSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after settleSendCoins: data=`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.settleSendCoins) { logger.warn( 'X-Com: SendCoinsClient: settleSendCoins without response data from endpoint', @@ -115,9 +124,14 @@ export class SendCoinsClient { async revertSettledSendCoins(args: SendCoinsArgs): Promise { logger.debug(`X-Com: revertSettledSendCoins against endpoint='${this.endpoint}'...`) try { - logger.debug(`X-Com: SendCoinsClient: revertSettledSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(revertSettledSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: revertSettledSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ revertSettledSendCoins: boolean }>( + revertSettledSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after revertSettledSendCoins: data=`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.revertSettledSendCoins) { diff --git a/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts b/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts new file mode 100644 index 000000000..3151bbb31 --- /dev/null +++ b/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts @@ -0,0 +1,19 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommunityInfo' + +export class PublicCommunityInfoLoggingView extends AbstractLoggingView { + public constructor(private self: PublicCommunityInfo) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + name: this.self.name, + description: this.self.description, + creationDate: this.dateToString(this.self.creationDate), + publicKey: this.self.publicKey, + } + } +} diff --git a/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts b/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts new file mode 100644 index 000000000..2df149133 --- /dev/null +++ b/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts @@ -0,0 +1,24 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs' + +export class SendCoinsArgsLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsArgs) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + recipientCommunityUuid: this.self.recipientCommunityUuid, + recipientUserIdentifier: this.self.recipientUserIdentifier, + creationDate: this.self.creationDate, + amount: this.decimalToString(this.self.amount), + memoLength: this.self.memo.length, + senderCommunityUuid: this.self.senderCommunityUuid, + senderUserUuid: this.self.senderUserUuid, + senderUserName: this.self.senderUserName.substring(0, 3), + senderAlias: this.self.senderAlias?.substring(0, 3), + } + } +} diff --git a/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts b/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts new file mode 100644 index 000000000..b605eb1db --- /dev/null +++ b/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts @@ -0,0 +1,20 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult' + +export class SendCoinsResultLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsResult) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + vote: this.self.vote, + recipGradidoID: this.self.recipGradidoID, + recipFirstName: this.self.recipFirstName?.substring(0, 3), + recipLastName: this.self.recipLastName?.substring(0, 3), + recipAlias: this.self.recipAlias?.substring(0, 3), + } + } +} diff --git a/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts b/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts new file mode 100644 index 000000000..696c96cfe --- /dev/null +++ b/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts @@ -0,0 +1,13 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Field, ObjectType } from 'type-graphql' + +@ObjectType() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class GetPublicKeyResult { + constructor(pubKey: string) { + this.publicKey = pubKey + } + + @Field(() => String) + publicKey: string +} diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 69b69070a..f19d606bd 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -3,14 +3,15 @@ import { IsNull } from '@dbTools/typeorm' import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' -// eslint-disable-next-line camelcase import { FederationClient as V1_0_FederationClient } from '@/federation/client/1_0/FederationClient' import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommunityInfo' import { FederationClientFactory } from '@/federation/client/FederationClientFactory' import { backendLogger as logger } from '@/server/logger' import { startCommunityAuthentication } from './authenticateCommunities' +import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view' import { ApiVersionType } from './enum/apiVersionType' export async function startValidateCommunities(timerInterval: number): Promise { @@ -37,7 +38,7 @@ export async function validateCommunities(): Promise { logger.debug(`Federation: found ${dbFederatedCommunities.length} dbCommunities`) for (const dbCom of dbFederatedCommunities) { - logger.debug('Federation: dbCom', dbCom) + logger.debug('Federation: dbCom', new FederatedCommunityLoggingView(dbCom)) const apiValueStrings: string[] = Object.values(ApiVersionType) logger.debug(`suppported ApiVersions=`, apiValueStrings) if (!apiValueStrings.includes(dbCom.apiVersion)) { @@ -53,7 +54,7 @@ export async function validateCommunities(): Promise { // eslint-disable-next-line camelcase if (client instanceof V1_0_FederationClient) { const pubKey = await client.getPublicKey() - if (pubKey && pubKey === dbCom.publicKey.toString()) { + if (pubKey && pubKey === dbCom.publicKey.toString('hex')) { await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.debug(`Federation: verified community with:`, dbCom.endPoint) const pubComInfo = await client.getPublicCommunityInfo() @@ -68,7 +69,7 @@ export async function validateCommunities(): Promise { logger.debug( 'Federation: received not matching publicKey:', pubKey, - dbCom.publicKey.toString(), + dbCom.publicKey.toString('hex'), ) } } @@ -82,10 +83,11 @@ async function writeForeignCommunity( dbCom: DbFederatedCommunity, pubInfo: PublicCommunityInfo, ): Promise { - if (!dbCom || !pubInfo || !(dbCom.publicKey.toString() === pubInfo.publicKey)) { + if (!dbCom || !pubInfo || !(dbCom.publicKey.toString('hex') === pubInfo.publicKey)) { + const pubInfoView = new PublicCommunityInfoLoggingView(pubInfo) logger.error( - `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${JSON.stringify( - pubInfo, + `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${pubInfoView.toString( + true, )}`, ) } else { diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 7e329926b..28ddf1c38 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -58,7 +58,8 @@ "@test/*": ["test/*"], /* external */ "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["@types", "node_modules/@types"], /* List of folders to include type definitions from. */ diff --git a/database/logging/AbstractLogging.view.ts b/database/logging/AbstractLogging.view.ts index a30254b86..e51f3823d 100644 --- a/database/logging/AbstractLogging.view.ts +++ b/database/logging/AbstractLogging.view.ts @@ -3,13 +3,18 @@ import util from 'util' import { Decimal } from 'decimal.js-light' export abstract class AbstractLoggingView { + // eslint-disable-next-line no-undef protected bufferStringFormat: BufferEncoding = 'hex' // This function gets called automatically when JSON.stringify() is called on this class instance // eslint-disable-next-line @typescript-eslint/no-explicit-any public abstract toJSON(): any - public toString(): string { - return JSON.stringify(this.toJSON(), null, 2) + public toString(compact = false): string { + if (compact) { + return JSON.stringify(this.toJSON()) + } else { + return JSON.stringify(this.toJSON(), null, 2) + } } // called form console.log or log4js logging functions diff --git a/database/logging/FederatedCommunityLogging.view.ts b/database/logging/FederatedCommunityLogging.view.ts new file mode 100644 index 000000000..4e36cc236 --- /dev/null +++ b/database/logging/FederatedCommunityLogging.view.ts @@ -0,0 +1,24 @@ +import { FederatedCommunity } from '../entity/FederatedCommunity' +import { AbstractLoggingView } from './AbstractLogging.view' + +export class FederatedCommunityLoggingView extends AbstractLoggingView { + public constructor(private self: FederatedCommunity) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + publicKey: this.self.publicKey.toString(this.bufferStringFormat), + apiVersion: this.self.apiVersion, + endPoint: this.self.endPoint, + lastAnnouncedAt: this.dateToString(this.self.lastAnnouncedAt), + verifiedAt: this.self.verifiedAt, + lastErrorAt: this.self.lastErrorAt, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/dht-node/.env.dist b/dht-node/.env.dist index 51728d3e1..fa07fc904 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -15,5 +15,5 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log FEDERATION_DHT_TOPIC=GRADIDO_HUB # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f FEDERATION_COMMUNITY_URL=http://localhost -# the api port is the dht baseport, which will be added with the supported api-versions, e.g. 1_0 = 5010 -FEDERATION_COMMUNITY_API_PORT=5000 +# comma separated values, which apis should be announced +FEDERATION_COMMUNITY_APIS=1_0 \ No newline at end of file diff --git a/dht-node/.env.template b/dht-node/.env.template index 1278f61be..324d2c3a7 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -20,4 +20,5 @@ FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL -FEDERATION_COMMUNITY_API_PORT=$FEDERATION_COMMUNITY_API_PORT +# comma separated values, which apis should be announced +FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS \ No newline at end of file diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 3459ec058..3599dd3c4 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -10,7 +10,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v3.2023-04-26', + EXPECTED: 'v4.2024-01-17', CURRENT: '', }, } @@ -39,7 +39,7 @@ const federation = { FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || 'GRADIDO_HUB', FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null, FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || 'http://localhost', - FEDERATION_COMMUNITY_API_PORT: process.env.FEDERATION_COMMUNITY_API_PORT || '5000', + FEDERATION_COMMUNITY_APIS: process.env.FEDERATION_COMMUNITY_APIS || '1_0', } // Check config version diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 536966591..dd17b7049 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -18,8 +18,8 @@ const ANNOUNCETIME = 30000 enum ApiVersionType { V1_0 = '1_0', - V1_1 = '1_1', - V2_0 = '2_0', + V1_1 = '1_1', // currently no changes + V2_0 = '2_0', // not exist } type CommunityApi = { api: string @@ -191,9 +191,11 @@ export const startDHT = async (topic: string): Promise => { } async function writeFederatedHomeCommunityEntries(pubKey: string): Promise { - const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) { + const homeApiVersions: CommunityApi[] = CONFIG.FEDERATION_COMMUNITY_APIS.split(',').map(function ( + api, + ) { const comApi: CommunityApi = { - api: apiEnum, + api, url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', } return comApi diff --git a/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts b/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts new file mode 100644 index 000000000..669170b98 --- /dev/null +++ b/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts @@ -0,0 +1,18 @@ +import { GetPublicCommunityInfoResult } from '@/graphql/api/1_0/model/GetPublicCommunityInfoResult' +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +export class GetPublicCommunityInfoResultLoggingView extends AbstractLoggingView { + public constructor(private self: GetPublicCommunityInfoResult) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + name: this.self.name, + description: this.self.description, + creationDate: this.dateToString(this.self.creationDate), + publicKey: this.self.publicKey, + } + } +} diff --git a/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts b/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts new file mode 100644 index 000000000..a12ff6372 --- /dev/null +++ b/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts @@ -0,0 +1,23 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' +import { SendCoinsArgs } from '@/graphql/api/1_0/model/SendCoinsArgs' + +export class SendCoinsArgsLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsArgs) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + recipientCommunityUuid: this.self.recipientCommunityUuid, + recipientUserIdentifier: this.self.recipientUserIdentifier, + creationDate: this.self.creationDate, + amount: this.decimalToString(this.self.amount), + memoLength: this.self.memo.length, + senderCommunityUuid: this.self.senderCommunityUuid, + senderUserUuid: this.self.senderUserUuid, + senderUserName: this.self.senderUserName.substring(0, 3), + senderAlias: this.self.senderAlias?.substring(0, 3), + } + } +} diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index 86ea480df..d51b3af93 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -7,7 +7,7 @@ import { Field, ObjectType } from 'type-graphql' // eslint-disable-next-line @typescript-eslint/no-unused-vars export class GetPublicCommunityInfoResult { constructor(dbCom: DbCommunity) { - this.publicKey = dbCom.publicKey.toString() + this.publicKey = dbCom.publicKey.toString('hex') this.name = dbCom.name this.description = dbCom.description this.creationDate = dbCom.creationDate diff --git a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts index 8f7b510cf..393fe3b65 100644 --- a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts @@ -3,6 +3,8 @@ import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFedCommunity } from '@entity/FederatedCommunity' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' import { LogError } from '@/server/LogError' import { OpenConnectionArgs } from '../model/OpenConnectionArgs' import { startAuthentication, startOpenConnectionCallback } from '../util/authenticateCommunity' @@ -11,7 +13,6 @@ import { CONFIG } from '@/config' import { AuthenticationArgs } from '../model/AuthenticationArgs' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class AuthenticationResolver { @Mutation(() => Boolean) async openConnection( @@ -28,7 +29,7 @@ export class AuthenticationResolver { if (!comA) { throw new LogError(`unknown requesting community with publicKey`, pubKeyBuf.toString('hex')) } - logger.debug(`Authentication: found requestedCom:`, comA) + logger.debug(`Authentication: found requestedCom:`, new CommunityLoggingView(comA)) // no await to respond immediatly and invoke callback-request asynchron void startOpenConnectionCallback(args, comA, CONFIG.FEDERATION_API) return true @@ -48,7 +49,10 @@ export class AuthenticationResolver { if (!fedComB) { throw new LogError(`unknown callback community with url`, args.url) } - logger.debug(`Authentication: found fedComB and start authentication:`, fedComB) + logger.debug( + `Authentication: found fedComB and start authentication:`, + new FederatedCommunityLoggingView(fedComB), + ) // no await to respond immediatly and invoke authenticate-request asynchron void startAuthentication(args.oneTimeCode, fedComB) return true @@ -61,13 +65,16 @@ export class AuthenticationResolver { ): Promise { logger.debug(`Authentication: authenticate() via apiVersion=1_0 ...`, args) const authCom = await DbCommunity.findOneByOrFail({ communityUuid: args.oneTimeCode }) - logger.debug('Authentication: found authCom:', authCom) + logger.debug('Authentication: found authCom:', new CommunityLoggingView(authCom)) if (authCom) { // TODO decrypt args.uuid with authCom.publicKey authCom.communityUuid = args.uuid authCom.authenticatedAt = new Date() await DbCommunity.save(authCom) - logger.debug('Authentication: store authCom.uuid successfully:', authCom) + logger.debug( + 'Authentication: store authCom.uuid successfully:', + new CommunityLoggingView(authCom), + ) const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) // TODO encrypt homeCom.uuid with homeCom.privateKey if (homeCom.communityUuid) { diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts index 339314f86..c1535b713 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts @@ -3,16 +3,19 @@ import { Query, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { GetPublicCommunityInfoResult } from '../model/GetPublicCommunityInfoResult' +import { GetPublicCommunityInfoResultLoggingView } from '../logger/GetPublicCommunityInfoResultLogging.view' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class PublicCommunityInfoResolver { @Query(() => GetPublicCommunityInfoResult) async getPublicCommunityInfo(): Promise { logger.debug(`getPublicCommunityInfo() via apiVersion=1_0 ...`) const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) const result = new GetPublicCommunityInfoResult(homeCom) - logger.debug(`getPublicCommunityInfo()-1_0... return publicInfo=${JSON.stringify(result)}`) + const publicInfoView = new GetPublicCommunityInfoResultLoggingView(result) + logger.debug( + `getPublicCommunityInfo()-1_0... return publicInfo=${publicInfoView.toString(true)}`, + ) return result } } diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts index bab0e25f5..3fb3b2c0d 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts @@ -5,7 +5,6 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom import { GetPublicKeyResult } from '../model/GetPublicKeyResult' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class PublicKeyResolver { @Query(() => GetPublicKeyResult) async getPublicKey(): Promise { @@ -16,7 +15,8 @@ export class PublicKeyResolver { apiVersion: '1_0', }, }) - logger.debug(`getPublicKey()-1_0... return publicKey=${homeCom.publicKey}`) - return new GetPublicKeyResult(homeCom.publicKey.toString()) + const publicKeyHex = homeCom.publicKey.toString('hex') + logger.debug(`getPublicKey()-1_0... return publicKey=${publicKeyHex}`) + return new GetPublicKeyResult(publicKeyHex) } } diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index aa6e2300e..dd5a81a45 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -1,5 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Arg, Args, Mutation, Resolver } from 'type-graphql' +import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction' @@ -16,27 +15,16 @@ import { findUserByIdentifier } from '@/graphql/util/findUserByIdentifier' import { SendCoinsResult } from '../model/SendCoinsResult' import Decimal from 'decimal.js-light' import { storeForeignUser } from '../util/storeForeignUser' +import { SendCoinsArgsLoggingView } from '../logger/SendCoinsArgsLogging.view' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class SendCoinsResolver { @Mutation(() => SendCoinsResult) async voteForSendCoins( @Arg('data') args: SendCoinsArgs, ): Promise { - logger.debug( - `voteForSendCoins() via apiVersion=1_0 ...`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - args.creationDate, - args.amount.toString(), - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - args.senderAlias, - ) + logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`, new SendCoinsArgsLoggingView(args)) const result = new SendCoinsResult() // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ @@ -167,19 +155,11 @@ export class SendCoinsResolver { pendingTx?.amount.toString(), args.amount.toString(), ) - throw new LogError( - `Can't find in revertSendCoins the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.NEW, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - ) + throw new LogError(`Can't find in revertSendCoins the pending receiver TX for `, { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.NEW, + transactionType: TransactionTypeId.RECEIVE, + }) } logger.debug(`revertSendCoins()-1_0... successfull`) return true @@ -193,15 +173,7 @@ export class SendCoinsResolver { @Arg('data') args: SendCoinsArgs, ): Promise { - logger.debug( - `settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${ - args.recipientCommunityUuid - }, userGradidoID=${args.recipientUserIdentifier}, balanceDate=${ - args.creationDate - },amount=${args.amount.valueOf()}, memo=${args.memo}, linkedUserCommunityUuid = ${ - args.senderCommunityUuid - }, userSenderIdentifier=${args.senderUserUuid}, userSenderName=${args.senderUserName}`, - ) + logger.debug(`settleSendCoins() via apiVersion=1_0 ...`, new SendCoinsArgsLoggingView(args)) // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ communityUuid: args.recipientCommunityUuid, @@ -256,17 +228,12 @@ export class SendCoinsResolver { } else { logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...') throw new LogError( - `Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.NEW, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, + `Can't find in settlePendingReceiveTransaction the pending receiver TX for `, + { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.NEW, + transactionTypeId: TransactionTypeId.RECEIVE, + }, ) } } @@ -322,19 +289,11 @@ export class SendCoinsResolver { } } else { logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...') - throw new LogError( - `Can't find in revertSettledSendCoins the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.SETTLED, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - ) + throw new LogError(`Can't find in revertSettledSendCoins the pending receiver TX for `, { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.SETTLED, + transactionTypeId: TransactionTypeId.RECEIVE, + }) } logger.debug(`revertSendCoins()-1_0... successfull`) return true diff --git a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts index 0af3475ef..b672fe7fd 100644 --- a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts +++ b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts @@ -9,13 +9,18 @@ import { AuthenticationClientFactory } from '@/client/AuthenticationClientFactor // eslint-disable-next-line camelcase import { AuthenticationClient as V1_0_AuthenticationClient } from '@/client/1_0/AuthenticationClient' import { AuthenticationArgs } from '../model/AuthenticationArgs' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' export async function startOpenConnectionCallback( args: OpenConnectionArgs, comA: DbCommunity, api: string, ): Promise { - logger.debug(`Authentication: startOpenConnectionCallback() with:`, args, comA) + logger.debug(`Authentication: startOpenConnectionCallback() with:`, { + args, + comA: new CommunityLoggingView(comA), + }) try { const homeFedCom = await DbFedCommunity.findOneByOrFail({ foreign: false, @@ -30,7 +35,10 @@ export async function startOpenConnectionCallback( // store oneTimeCode in requestedCom.community_uuid as authenticate-request-identifier comA.communityUuid = oneTimeCode.toString() await DbCommunity.save(comA) - logger.debug(`Authentication: stored oneTimeCode in requestedCom:`, comA) + logger.debug( + `Authentication: stored oneTimeCode in requestedCom:`, + new CommunityLoggingView(comA), + ) const client = AuthenticationClientFactory.getInstance(fedComA) // eslint-disable-next-line camelcase @@ -57,7 +65,10 @@ export async function startAuthentication( oneTimeCode: string, fedComB: DbFedCommunity, ): Promise { - logger.debug(`Authentication: startAuthentication()...`, oneTimeCode, fedComB) + logger.debug(`Authentication: startAuthentication()...`, { + oneTimeCode, + fedComB: new FederatedCommunityLoggingView(fedComB), + }) try { const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) @@ -88,7 +99,10 @@ export async function startAuthentication( callbackCom.communityUuid = fedComUuid callbackCom.authenticatedAt = new Date() await DbCommunity.save(callbackCom) - logger.debug('Authentication: Community Authentication successful:', callbackCom) + logger.debug( + 'Authentication: Community Authentication successful:', + new CommunityLoggingView(callbackCom), + ) } else { logger.error('Authentication: Community Authentication failed:', authenticationArgs) } diff --git a/federation/tsconfig.json b/federation/tsconfig.json index 50ce9d0c7..0f96e80e5 100644 --- a/federation/tsconfig.json +++ b/federation/tsconfig.json @@ -60,7 +60,8 @@ /* external */ "@typeorm/*": ["../backend/src/typeorm/*", "../../backend/src/typeorm/*"], "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */ From dd53870dcfa8a53356a562a5272b02c66813d3e4 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 13:14:05 +0100 Subject: [PATCH 38/85] use hex format --- backend/src/graphql/model/FederatedCommunity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/model/FederatedCommunity.ts b/backend/src/graphql/model/FederatedCommunity.ts index 856a10d23..61ffd8f5b 100644 --- a/backend/src/graphql/model/FederatedCommunity.ts +++ b/backend/src/graphql/model/FederatedCommunity.ts @@ -6,7 +6,7 @@ export class FederatedCommunity { constructor(dbCom: DbFederatedCommunity) { this.id = dbCom.id this.foreign = dbCom.foreign - this.publicKey = dbCom.publicKey.toString() + this.publicKey = dbCom.publicKey.toString('hex') this.url = (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + dbCom.apiVersion this.lastAnnouncedAt = dbCom.lastAnnouncedAt From 9e0b1f72e83bc390330f8d40ff8ab4b3f01558aa Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 14:36:18 +0100 Subject: [PATCH 39/85] fix test --- dht-node/jest.config.js | 5 +++++ dht-node/src/dht_node/index.test.ts | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js index 6540cc68f..12543f8e2 100644 --- a/dht-node/jest.config.js +++ b/dht-node/jest.config.js @@ -21,6 +21,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': // eslint-disable-next-line n/no-process-env process.env.NODE_ENV === 'development' diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index 4370a2528..fc2ce7d12 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -14,6 +14,7 @@ import { CONFIG } from '@/config' import { startDHT } from './index' CONFIG.FEDERATION_DHT_SEED = '64ebcb0e3ad547848fef4197c6e2332f' +CONFIG.FEDERATION_COMMUNITY_APIS = '1_0,1_1,2_0' jest.mock('@hyperswarm/dht') @@ -248,7 +249,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'o\', "no-json string" is not valid JSON'), + new SyntaxError('Unexpected token o in JSON at position 1'), ) }) }) @@ -267,7 +268,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'i\', "invalid ty"... is not valid JSON'), + new SyntaxError('Unexpected token i in JSON at position 0'), ) }) }) @@ -291,7 +292,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'a\', "api,url,in"... is not valid JSON'), + new SyntaxError('Unexpected token a in JSON at position 0'), ) }) }) From 54d6eb03c562b0e0995051f2608c383e8bda3134 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 19:59:05 +0100 Subject: [PATCH 40/85] fix missing file --- dht-node/jest.config.js | 2 +- dht-node/src/dht_node/ApiVersionType.ts | 5 +++++ dht-node/src/dht_node/index.ts | 9 ++++----- 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 dht-node/src/dht_node/ApiVersionType.ts diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js index 12543f8e2..0bb09f0e4 100644 --- a/dht-node/jest.config.js +++ b/dht-node/jest.config.js @@ -7,7 +7,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 83, + lines: 82, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/dht-node/src/dht_node/ApiVersionType.ts b/dht-node/src/dht_node/ApiVersionType.ts new file mode 100644 index 000000000..84eb3e39b --- /dev/null +++ b/dht-node/src/dht_node/ApiVersionType.ts @@ -0,0 +1,5 @@ +export enum ApiVersionType { + V1_0 = '1_0', + V1_1 = '1_1', // currently no changes + V2_0 = '2_0', // not exist +} diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index dd17b7049..657dac8d0 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' import { logger } from '@/server/logger' +import { ApiVersionType } from './ApiVersionType' const KEY_SECRET_SEEDBYTES = 32 @@ -16,11 +17,6 @@ const SUCCESSTIME = 120000 const ERRORTIME = 240000 const ANNOUNCETIME = 30000 -enum ApiVersionType { - V1_0 = '1_0', - V1_1 = '1_1', // currently no changes - V2_0 = '2_0', // not exist -} type CommunityApi = { api: string url: string @@ -194,6 +190,9 @@ async function writeFederatedHomeCommunityEntries(pubKey: string): Promise Date: Fri, 19 Jan 2024 11:42:32 +0100 Subject: [PATCH 41/85] fix lint --- dht-node/src/dht_node/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 657dac8d0..c5f5cf4c2 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' import { logger } from '@/server/logger' + import { ApiVersionType } from './ApiVersionType' const KEY_SECRET_SEEDBYTES = 32 From 74186e21ae23afa3049328db3e5802257c63a9db Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 13:40:21 +0100 Subject: [PATCH 42/85] more logging classes, fix test --- database/logging/ContributionLogging.view.ts | 45 ++++++++++++++ .../ContributionMessageLogging.view.ts | 30 ++++++++++ .../logging/DltTransactionLogging.view.ts | 23 +++++++ .../logging/PendingTransactionLogging.view.ts | 27 +++++++++ database/logging/TransactionLogging.view.ts | 56 +++++++++++++++++ database/logging/UserContactLogging.view.ts | 35 +++++++++++ database/logging/UserLogging.view.ts | 60 +++++++++++++++++++ database/logging/UserRoleLogging.view.ts | 22 +++++++ federation/jest.config.js | 5 ++ .../PublicCommunityInfoResolver.test.ts | 7 ++- .../1_0/resolver/PublicKeyResolver.test.ts | 7 ++- .../api/1_0/resolver/SendCoinsResolver.ts | 16 ++++- .../api/1_0/util/authenticateCommunity.ts | 2 +- .../util/revertSettledReceiveTransaction.ts | 27 ++++++--- .../util/settlePendingReceiveTransaction.ts | 12 +++- .../graphql/api/1_0/util/storeForeignUser.ts | 15 ++--- .../1_1/resolver/PublicKeyResolver.test.ts | 7 ++- 17 files changed, 369 insertions(+), 27 deletions(-) create mode 100644 database/logging/ContributionLogging.view.ts create mode 100644 database/logging/ContributionMessageLogging.view.ts create mode 100644 database/logging/DltTransactionLogging.view.ts create mode 100644 database/logging/PendingTransactionLogging.view.ts create mode 100644 database/logging/TransactionLogging.view.ts create mode 100644 database/logging/UserContactLogging.view.ts create mode 100644 database/logging/UserLogging.view.ts create mode 100644 database/logging/UserRoleLogging.view.ts diff --git a/database/logging/ContributionLogging.view.ts b/database/logging/ContributionLogging.view.ts new file mode 100644 index 000000000..c924525d2 --- /dev/null +++ b/database/logging/ContributionLogging.view.ts @@ -0,0 +1,45 @@ +import { Contribution } from '../entity/Contribution' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class ContributionLoggingView extends AbstractLoggingView { + public constructor(private self: Contribution) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + createdAt: this.dateToString(this.self.createdAt), + resubmissionAt: this.dateToString(this.self.resubmissionAt), + contributionDate: this.dateToString(this.self.contributionDate), + memoLength: this.self.memo.length, + amount: this.decimalToString(this.self.amount), + moderatorId: this.self.moderatorId, + contributionLinkId: this.self.contributionLinkId, + confirmedBy: this.self.confirmedBy, + confirmedAt: this.dateToString(this.self.confirmedAt), + deniedBy: this.self.deniedBy, + deniedAt: this.dateToString(this.self.deniedAt), + contributionType: this.self.contributionType, + contributionStatus: this.self.contributionStatus, + transactionId: this.self.transactionId, + updatedAt: this.dateToString(this.self.updatedAt), + updatedBy: this.self.updatedBy, + deletedAt: this.dateToString(this.self.deletedAt), + deletedBy: this.self.deletedBy, + messages: this.self.messages + ? this.self.messages.map((message) => new ContributionMessageLoggingView(message).toJSON()) + : undefined, + transaction: this.self.transaction + ? new TransactionLoggingView(this.self.transaction).toJSON() + : { id: this.self.transactionId }, + } + } +} diff --git a/database/logging/ContributionMessageLogging.view.ts b/database/logging/ContributionMessageLogging.view.ts new file mode 100644 index 000000000..d05c000bb --- /dev/null +++ b/database/logging/ContributionMessageLogging.view.ts @@ -0,0 +1,30 @@ +import { ContributionMessage } from '../entity/ContributionMessage' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class ContributionMessageLoggingView extends AbstractLoggingView { + public constructor(private self: ContributionMessage) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + contribution: this.self.contribution + ? new ContributionLoggingView(this.self.contribution).toJSON() + : { id: this.self.contributionId }, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + messageLength: this.self.message.length, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + deletedAt: this.dateToString(this.self.deletedAt), + deletedBy: this.self.deletedBy, + type: this.self.type, + isModerator: this.self.isModerator, + } + } +} diff --git a/database/logging/DltTransactionLogging.view.ts b/database/logging/DltTransactionLogging.view.ts new file mode 100644 index 000000000..7d1681ce2 --- /dev/null +++ b/database/logging/DltTransactionLogging.view.ts @@ -0,0 +1,23 @@ +import { DltTransaction } from '../entity/DltTransaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' + +export class DltTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: DltTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + transaction: this.self.transaction + ? new TransactionLoggingView(this.self.transaction).toJSON() + : { id: this.self.transactionId }, + messageId: this.self.messageId, + verified: this.self.verified, + createdAt: this.dateToString(this.self.createdAt), + verifiedAt: this.dateToString(this.self.verifiedAt), + } + } +} diff --git a/database/logging/PendingTransactionLogging.view.ts b/database/logging/PendingTransactionLogging.view.ts new file mode 100644 index 000000000..84b7f35b9 --- /dev/null +++ b/database/logging/PendingTransactionLogging.view.ts @@ -0,0 +1,27 @@ +/* eslint-disable no-unused-vars */ +import { PendingTransaction } from '../entity/PendingTransaction' +import { Transaction } from '../entity/Transaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' + +// TODO: move enum into database, maybe rename database +enum PendingTransactionState { + NEW = 1, + PENDING = 2, + SETTLED = 3, + REVERTED = 4, +} + +export class PendingTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: PendingTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + ...new TransactionLoggingView(this.self as Transaction).toJSON(), + state: PendingTransactionState[this.self.state], + } + } +} diff --git a/database/logging/TransactionLogging.view.ts b/database/logging/TransactionLogging.view.ts new file mode 100644 index 000000000..7912c7e5d --- /dev/null +++ b/database/logging/TransactionLogging.view.ts @@ -0,0 +1,56 @@ +/* eslint-disable no-unused-vars */ +import { Transaction } from '../entity/Transaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { DltTransactionLoggingView } from './DltTransactionLogging.view' + +// TODO: move enum into database, maybe rename database +enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} + +export class TransactionLoggingView extends AbstractLoggingView { + public constructor(private self: Transaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + previous: this.self.previous, + typeId: TransactionTypeId[this.self.typeId], + transactionLinkId: this.self.transactionLinkId, + amount: this.decimalToString(this.self.amount), + balance: this.decimalToString(this.self.balance), + balanceDate: this.dateToString(this.self.balanceDate), + decay: this.decimalToString(this.self.decay), + decayStart: this.dateToString(this.self.decayStart), + memoLength: this.self.memo.length, + creationDate: this.dateToString(this.self.creationDate), + userId: this.self.userId, + userCommunityUuid: this.self.userCommunityUuid, + userGradidoId: this.self.userGradidoID, + userName: this.self.userName?.substring(0, 3) + '...', + linkedUserId: this.self.linkedUserId, + linkedUserCommunityUuid: this.self.linkedUserCommunityUuid, + linkedUserGradidoID: this.self.linkedUserGradidoID, + linkedUserName: this.self.linkedUserName?.substring(0, 3) + '...', + linkedTransactionId: this.self.linkedTransactionId, + contribution: this.self.contribution + ? new ContributionLoggingView(this.self.contribution) + : undefined, + dltTransaction: this.self.dltTransaction + ? new DltTransactionLoggingView(this.self.dltTransaction).toJSON() + : undefined, + previousTransaction: this.self.previousTransaction + ? new TransactionLoggingView(this.self.previousTransaction).toJSON() + : undefined, + } + } +} diff --git a/database/logging/UserContactLogging.view.ts b/database/logging/UserContactLogging.view.ts new file mode 100644 index 000000000..ebc05843a --- /dev/null +++ b/database/logging/UserContactLogging.view.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-unused-vars */ +import { UserContact } from '../entity/UserContact' +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +enum OptInType { + EMAIL_OPT_IN_REGISTER = 1, + EMAIL_OPT_IN_RESET_PASSWORD = 2, +} + +export class UserContactLoggingView extends AbstractLoggingView { + public constructor(private self: UserContact) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + type: this.self.type, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + email: this.self.email?.substring(0, 3) + '...', + emailVerificationCode: this.self.emailVerificationCode?.substring(0, 4) + '...', + emailOptInTypeId: OptInType[this.self.emailOptInTypeId], + emailResendCount: this.self.emailResendCount, + emailChecked: this.self.emailChecked, + phone: this.self.phone ? this.self.phone.substring(0, 3) + '...' : undefined, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + deletedAt: this.dateToString(this.self.deletedAt), + } + } +} diff --git a/database/logging/UserLogging.view.ts b/database/logging/UserLogging.view.ts new file mode 100644 index 000000000..19b3ca911 --- /dev/null +++ b/database/logging/UserLogging.view.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-unused-vars */ +import { User } from '../entity/User' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' +import { UserContactLoggingView } from './UserContactLogging.view' +import { UserRoleLoggingView } from './UserRoleLogging.view' + +enum PasswordEncryptionType { + NO_PASSWORD = 0, + EMAIL = 1, + GRADIDO_ID = 2, +} + +export class UserLoggingView extends AbstractLoggingView { + public constructor(private self: User) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + gradidoID: this.self.gradidoID, + communityUuid: this.self.communityUuid, + alias: this.self.alias?.substring(0, 3) + '...', + emailContact: this.self.emailContact + ? new UserContactLoggingView(this.self.emailContact).toJSON() + : { id: this.self.emailId }, + firstName: this.self.firstName?.substring(0, 3) + '...', + lastName: this.self.lastName?.substring(0, 3) + '...', + createdAt: this.dateToString(this.self.createdAt), + deletedAt: this.dateToString(this.self.deletedAt), + passwordEncryptionType: this.self.passwordEncryptionType as PasswordEncryptionType, + language: this.self.language, + hideAmountGDD: this.self.hideAmountGDD, + hideAmountGDT: this.self.hideAmountGDT, + userRoles: this.self.userRoles + ? this.self.userRoles.map((userRole) => new UserRoleLoggingView(userRole).toJSON()) + : undefined, + referrerId: this.self.referrerId, + contributionLinkId: this.self.contributionLinkId, + publisherId: this.self.publisherId, + contributions: this.self.contributions + ? this.self.contributions.map((contribution) => + new ContributionLoggingView(contribution).toJSON(), + ) + : undefined, + messages: this.self.messages + ? this.self.messages.map((message) => new ContributionMessageLoggingView(message).toJSON()) + : undefined, + userContacts: this.self.userContacts + ? this.self.userContacts.map((userContact) => + new UserContactLoggingView(userContact).toJSON(), + ) + : undefined, + } + } +} diff --git a/database/logging/UserRoleLogging.view.ts b/database/logging/UserRoleLogging.view.ts new file mode 100644 index 000000000..19050367b --- /dev/null +++ b/database/logging/UserRoleLogging.view.ts @@ -0,0 +1,22 @@ +import { UserRole } from '../entity/UserRole' +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class UserRoleLoggingView extends AbstractLoggingView { + public constructor(private self: UserRole) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + role: this.self.role, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/federation/jest.config.js b/federation/jest.config.js index bd41344f5..42bac0002 100644 --- a/federation/jest.config.js +++ b/federation/jest.config.js @@ -24,6 +24,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': process.env.NODE_ENV === 'development' ? '/../database/src/$1' diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts index 08544834f..2f83b4819 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts @@ -46,7 +46,10 @@ describe('PublicCommunityInfoResolver', () => { homeCom.name = 'Community-Name' homeCom.description = 'Community-Description' homeCom.creationDate = new Date() - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '316f2951501f27c664e188d5128505917e8673e8bebce141f86e70907e782a08', + 'hex', + ) await DbCommunity.insert(homeCom) }) @@ -57,7 +60,7 @@ describe('PublicCommunityInfoResolver', () => { name: 'Community-Name', description: 'Community-Description', creationDate: homeCom.creationDate?.toISOString(), - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '316f2951501f27c664e188d5128505917e8673e8bebce141f86e70907e782a08', }, }, }) diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts index 83c024c9f..eafd9cba7 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts @@ -39,7 +39,10 @@ describe('PublicKeyResolver', () => { homeCom.foreign = false homeCom.apiVersion = '1_0' homeCom.endPoint = 'endpoint-url' - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', + 'hex', + ) await DbFederatedCommunity.insert(homeCom) }) @@ -47,7 +50,7 @@ describe('PublicKeyResolver', () => { await expect(query({ query: getPublicKeyQuery })).resolves.toMatchObject({ data: { getPublicKey: { - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', }, }, }) diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index dd5a81a45..e90a7818c 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -1,5 +1,6 @@ import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' import { Community as DbCommunity } from '@entity/Community' import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction' import { SendCoinsArgs } from '../model/SendCoinsArgs' @@ -140,7 +141,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx) + logger.debug( + 'XCom: revertSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if (pendingTx && pendingTx.amount.toString() === args.amount.toString()) { logger.debug('XCom: revertSendCoins matching pendingTX for remove...') try { @@ -204,7 +208,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString()) + logger.debug( + 'XCom: settleSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if ( pendingTx && pendingTx.amount.toString() === args.amount.toString() && @@ -274,7 +281,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx) + logger.debug( + 'XCom: revertSettledSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if ( pendingTx && pendingTx.amount.toString() === args.amount.toString() && diff --git a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts index b672fe7fd..1d3365d9c 100644 --- a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts +++ b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts @@ -89,7 +89,7 @@ export async function startAuthentication( logger.debug( `Authentication: received communityUUid for callbackFedCom:`, fedComUuid, - fedComB, + new FederatedCommunityLoggingView(fedComB), ) const callbackCom = await DbCommunity.findOneByOrFail({ foreign: true, diff --git a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts index 4b1075cb2..bb5adec5c 100644 --- a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts @@ -15,6 +15,10 @@ import { federationLogger as logger } from '@/server/logger' import { getLastTransaction } from '@/graphql/util/getLastTransaction' import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { UserLoggingView } from '@logging/UserLogging.view' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' +import { TransactionLoggingView } from '@logging/TransactionLogging.view' export async function revertSettledReceiveTransaction( homeCom: DbCommunity, @@ -30,7 +34,11 @@ export async function revertSettledReceiveTransaction( logger.debug(`start Transaction for write-access...`) try { - logger.info('X-Com: revertSettledReceiveTransaction:', homeCom, receiverUser, pendingTx) + logger.info('X-Com: revertSettledReceiveTransaction:', { + homeCom: new CommunityLoggingView(homeCom), + receiverUser: new UserLoggingView(receiverUser), + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) // ensure that no other pendingTx with the same sender or recipient exists const openSenderPendingTx = await DbPendingTransaction.count({ @@ -68,6 +76,7 @@ export async function revertSettledReceiveTransaction( pendingTx.balanceDate.toISOString(), ) logger.debug(`GradidoID:`, lastTransaction?.userGradidoID, pendingTx.userGradidoID) + // todo: Data privacy: personal user data in log file? logger.debug(`Name:`, lastTransaction?.userName, pendingTx.userName) logger.debug(`amount:`, lastTransaction?.amount.toString(), pendingTx.amount.toString()) logger.debug(`memo:`, lastTransaction?.memo, pendingTx.memo) @@ -90,7 +99,10 @@ export async function revertSettledReceiveTransaction( lastTransaction.linkedUserName === pendingTx.linkedUserName ) { await queryRunner.manager.remove(dbTransaction, lastTransaction) - logger.debug(`X-Com: revert settlement receive Transaction removed:`, lastTransaction) + logger.debug( + `X-Com: revert settlement receive Transaction removed:`, + new TransactionLoggingView(lastTransaction), + ) // and mark the pendingTx in the pending_transactions table as reverted pendingTx.state = PendingTransactionState.REVERTED await queryRunner.manager.save(DbPendingTransaction, pendingTx) @@ -98,12 +110,11 @@ export async function revertSettledReceiveTransaction( await queryRunner.commitTransaction() logger.debug(`commit revert settlement recipient Transaction successful...`) } else { - // TODO: if the last TX is not equivelant to pendingTX, the transactions must be corrected in EXPERT-MODE - throw new LogError( - `X-Com: missmatching transaction order for revert settlement!`, - lastTransaction, - pendingTx, - ) + // TODO: if the last TX is not equivalent to pendingTX, the transactions must be corrected in EXPERT-MODE + throw new LogError(`X-Com: mismatching transaction order for revert settlement!`, { + lastTransaction: lastTransaction ? new TransactionLoggingView(lastTransaction) : 'null', + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) } /* diff --git a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts index e73e7a5fd..0eadbe1c2 100644 --- a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts @@ -17,6 +17,10 @@ import { getLastTransaction } from '@/graphql/util/getLastTransaction' import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK' import { calculateRecipientBalance } from './calculateRecipientBalance' import Decimal from 'decimal.js-light' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { UserLoggingView } from '@logging/UserLogging.view' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' +import { TransactionLoggingView } from '@logging/TransactionLogging.view' export async function settlePendingReceiveTransaction( homeCom: DbCommunity, @@ -32,7 +36,11 @@ export async function settlePendingReceiveTransaction( logger.debug(`start Transaction for write-access...`) try { - logger.info('X-Com: settlePendingReceiveTransaction:', homeCom, receiverUser, pendingTx) + logger.info('X-Com: settlePendingReceiveTransaction:', { + homeCom: new CommunityLoggingView(homeCom), + receiverUser: new UserLoggingView(receiverUser), + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) // ensure that no other pendingTx with the same sender or recipient exists const openSenderPendingTx = await DbPendingTransaction.count({ @@ -84,7 +92,7 @@ export async function settlePendingReceiveTransaction( transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null transactionReceive.linkedTransactionId = pendingTx.linkedTransactionId await queryRunner.manager.insert(dbTransaction, transactionReceive) - logger.debug(`receive Transaction inserted: ${dbTransaction}`) + logger.debug(`receive Transaction inserted: ${new TransactionLoggingView(transactionReceive)}`) // and mark the pendingTx in the pending_transactions table as settled pendingTx.state = PendingTransactionState.SETTLED diff --git a/federation/src/graphql/api/1_0/util/storeForeignUser.ts b/federation/src/graphql/api/1_0/util/storeForeignUser.ts index eeeb76a8f..861702d11 100644 --- a/federation/src/graphql/api/1_0/util/storeForeignUser.ts +++ b/federation/src/graphql/api/1_0/util/storeForeignUser.ts @@ -2,6 +2,8 @@ import { User as DbUser } from '@entity/User' import { federationLogger as logger } from '@/server/logger' import { SendCoinsArgs } from '../model/SendCoinsArgs' +import { UserLoggingView } from '@logging/UserLogging.view' +import { SendCoinsArgsLoggingView } from '../logger/SendCoinsArgsLogging.view' export async function storeForeignUser(args: SendCoinsArgs): Promise { if (args.senderCommunityUuid !== null && args.senderUserUuid !== null) { @@ -34,7 +36,7 @@ export async function storeForeignUser(args: SendCoinsArgs): Promise { } foreignUser.gradidoID = args.senderUserUuid foreignUser = await DbUser.save(foreignUser) - logger.debug('X-Com: new foreignUser inserted:', foreignUser) + logger.debug('X-Com: new foreignUser inserted:', new UserLoggingView(foreignUser)) return true } else if ( @@ -43,14 +45,13 @@ export async function storeForeignUser(args: SendCoinsArgs): Promise { args.senderUserName.slice(args.senderUserName.indexOf(' '), args.senderUserName.length) || user.alias !== args.senderAlias ) { - logger.warn( - 'X-Com: foreignUser still exists, but with different name or alias:', - user, - args, - ) + logger.warn('X-Com: foreignUser still exists, but with different name or alias:', { + user: new UserLoggingView(user), + args: new SendCoinsArgsLoggingView(args), + }) return false } else { - logger.debug('X-Com: foreignUser still exists...:', user) + logger.debug('X-Com: foreignUser still exists...:', new UserLoggingView(user)) return true } } catch (err) { diff --git a/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts b/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts index d41b53263..7ccec73af 100644 --- a/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts +++ b/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts @@ -39,7 +39,10 @@ describe('PublicKeyResolver', () => { homeCom.foreign = false homeCom.apiVersion = '1_0' homeCom.endPoint = 'endpoint-url' - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', + 'hex', + ) await DbFederatedCommunity.insert(homeCom) }) @@ -47,7 +50,7 @@ describe('PublicKeyResolver', () => { await expect(query({ query: getPublicKeyQuery })).resolves.toMatchObject({ data: { getPublicKey: { - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', }, }, }) From f7a680c2af8d4d941b35fcb6de193be8731c071e Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 14:20:47 +0100 Subject: [PATCH 43/85] fix test --- backend/jest.config.js | 5 + .../federation/validateCommunities.test.ts | 8 +- .../resolver/CommunityResolver.test.ts | 100 ++++++++++++++---- 3 files changed, 86 insertions(+), 27 deletions(-) diff --git a/backend/jest.config.js b/backend/jest.config.js index 32606c382..f7edec3dd 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -28,6 +28,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': // eslint-disable-next-line n/no-process-env process.env.NODE_ENV === 'development' diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 4f6339771..9ff8d545f 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -68,7 +68,7 @@ describe('validate Communities', () => { return { data: {} } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -113,7 +113,7 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -195,7 +195,7 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -315,7 +315,7 @@ describe('validate Communities', () => { } as Response }) const variables3 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '2_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 011670e87..4f42e9455 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -62,7 +62,10 @@ describe('CommunityResolver', () => { homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) homeCom1.apiVersion = '1_0' homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() @@ -70,7 +73,10 @@ describe('CommunityResolver', () => { homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false - homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom2.publicKey = Buffer.from( + '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', + 'hex', + ) homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() @@ -78,7 +84,10 @@ describe('CommunityResolver', () => { homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false - homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom3.publicKey = Buffer.from( + '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', + 'hex', + ) homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() @@ -92,7 +101,9 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', + ), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -103,7 +114,9 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', + ), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -114,7 +127,9 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + ), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -134,7 +149,10 @@ describe('CommunityResolver', () => { foreignCom1 = DbFederatedCommunity.create() foreignCom1.foreign = true - foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom1.publicKey = Buffer.from( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + 'hex', + ) foreignCom1.apiVersion = '1_0' foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() @@ -142,7 +160,10 @@ describe('CommunityResolver', () => { foreignCom2 = DbFederatedCommunity.create() foreignCom2.foreign = true - foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom2.publicKey = Buffer.from( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + 'hex', + ) foreignCom2.apiVersion = '1_1' foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() @@ -150,7 +171,10 @@ describe('CommunityResolver', () => { foreignCom3 = DbFederatedCommunity.create() foreignCom3.foreign = true - foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom3.publicKey = Buffer.from( + '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', + 'hex', + ) foreignCom3.apiVersion = '1_2' foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() @@ -164,7 +188,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom3.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -175,7 +199,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom2.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -186,7 +210,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom1.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -197,7 +221,9 @@ describe('CommunityResolver', () => { { id: 6, foreign: foreignCom3.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', + ), url: expect.stringMatching('http://remotehost/api/1_2'), lastAnnouncedAt: null, verifiedAt: null, @@ -208,7 +234,9 @@ describe('CommunityResolver', () => { { id: 5, foreign: foreignCom2.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + ), url: expect.stringMatching('http://remotehost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -219,7 +247,9 @@ describe('CommunityResolver', () => { { id: 4, foreign: foreignCom1.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + ), url: expect.stringMatching('http://remotehost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -264,8 +294,14 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') - homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) + homeCom1.privateKey = Buffer.from( + 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', + 'hex', + ) homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -302,8 +338,14 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') - homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) + homeCom1.privateKey = Buffer.from( + 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', + 'hex', + ) homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -314,8 +356,14 @@ describe('CommunityResolver', () => { foreignCom1 = DbCommunity.create() foreignCom1.foreign = true foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from('publicKey-stage-2_Community') - foreignCom1.privateKey = Buffer.from('privateKey-stage-2_Community') + foreignCom1.publicKey = Buffer.from( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + 'hex', + ) + foreignCom1.privateKey = Buffer.from( + 'd967220052995169b20b89a0c6190ee8aa9ca501d7a6df81c49a97003edca2ed724d69eaf55e62290d699d7c3ec8b44985fffd57def98d51b2202f2bd82330b3', + 'hex', + ) // foreignCom1.communityUuid = 'Stage2-Com-UUID' // foreignCom1.authenticatedAt = new Date() foreignCom1.name = 'Stage-2_Community-name' @@ -326,8 +374,14 @@ describe('CommunityResolver', () => { foreignCom2 = DbCommunity.create() foreignCom2.foreign = true foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from('publicKey-stage-3_Community') - foreignCom2.privateKey = Buffer.from('privateKey-stage-3_Community') + foreignCom2.publicKey = Buffer.from( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + 'hex', + ) + foreignCom2.privateKey = Buffer.from( + '0ae8921a204bd27e1ba834ffa2f4480cca867b4def783934f3032e19c54d6e7c9fb3233eff07a0086f6bd8486e7220136ce941abdd51d268bfaca0cc3181f162', + 'hex', + ) foreignCom2.communityUuid = 'Stage3-Com-UUID' foreignCom2.authenticatedAt = new Date() foreignCom2.name = 'Stage-3_Community-name' From a1776ae67985193ca6836350547acb428bf4a34c Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 17:36:26 +0100 Subject: [PATCH 44/85] fix test, json error message differ from node version to node version --- dht-node/src/dht_node/index.test.ts | 29 ++++++++++++++++++++++++++--- dht-node/src/dht_node/index.ts | 13 +++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index fc2ce7d12..c31869551 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -249,7 +249,30 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token o in JSON at position 1'), + new SyntaxError('Unexpected token \'o\', "no-json string" is not valid JSON'), + ) + }) + }) + + describe('with receiving non ascii character', () => { + beforeEach(() => { + jest.clearAllMocks() + // containing non-ascii character copyright symbol, U+00A9 + socketEventMocks.data(Buffer.from('48656C6C6F2C20C2A92048656C6C6F21', 'hex')) + /* + const buffer = Buffer.from('48656C6C6F2C20C2A92048656C6C6F21', 'hex') + for (const byte of buffer) { + console.log('byte: %o', byte) + if (byte > 127) { + console.log('non ascii char spotted') + } + } + */ + }) + + it('logs the binary data as hex', () => { + expect(logger.warn).toBeCalledWith( + 'received non ascii character, content as hex: 48656c6c6f2c20c2a92048656c6c6f21', ) }) }) @@ -268,7 +291,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token i in JSON at position 0'), + new SyntaxError('Unexpected token \'i\', "invalid ty"... is not valid JSON'), ) }) }) @@ -292,7 +315,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token a in JSON at position 0'), + new SyntaxError('Unexpected token \'a\', "api,url,in"... is not valid JSON'), ) }) }) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index c5f5cf4c2..fab67e839 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -25,6 +25,15 @@ type CommunityApi = { type KeyPair = { publicKey: Buffer; secretKey: Buffer } +function isAscii(buffer: Buffer): boolean { + for (const byte of buffer) { + if (byte > 127) { + return false + } + } + return true +} + export const startDHT = async (topic: string): Promise => { try { const TOPIC = DHT.hash(Buffer.from(topic)) @@ -57,6 +66,10 @@ export const startDHT = async (topic: string): Promise => { ) return } + if (!isAscii(data)) { + logger.warn(`received non ascii character, content as hex: ${data.toString('hex')}`) + return + } logger.info(`data: ${data.toString('ascii')}`) const recApiVersions: CommunityApi[] = JSON.parse(data.toString('ascii')) From 0a553b88961729afd5b884f7a2907f8f673011fd Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 17:57:43 +0100 Subject: [PATCH 45/85] update deployment config --- deployment/bare_metal/.env.dist | 6 +++--- dht-node/.env.template | 2 +- federation/.env.template | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index eb1e45f79..96df6f81b 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -25,8 +25,8 @@ DATABASE_CONFIG_VERSION=v1.2022-03-18 BACKEND_CONFIG_VERSION=v21.2024-01-06 FRONTEND_CONFIG_VERSION=v5.2024-01-08 ADMIN_CONFIG_VERSION=v2.2024-01-04 -FEDERATION_CONFIG_VERSION=v1.2023-01-09 -FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 +FEDERATION_CONFIG_VERSION=v2.2023-08-24 +FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17 FEDERATION_DHT_TOPIC=GRADIDO_HUB @@ -76,7 +76,7 @@ FEDERATION_COMMUNITY_API_PORT=5000 FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 # comma separated list of api-versions, which cause starting several federation modules -FEDERATION_COMMUNITY_APIS=1_0,1_1 +FEDERATION_COMMUNITY_APIS=1_0 # externe gradido services (more added in future) GDT_API_URL=https://gdt.gradido.net diff --git a/dht-node/.env.template b/dht-node/.env.template index 3517ccc9a..629aaf069 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -1,5 +1,5 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=v3.2023-04-26 +CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # Database DB_HOST=localhost diff --git a/federation/.env.template b/federation/.env.template index 91fb1c692..9a029c3d1 100644 --- a/federation/.env.template +++ b/federation/.env.template @@ -1,5 +1,5 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=v2.2023-08-24 +CONFIG_VERSION=$FEDERATION_CONFIG_VERSION LOG_LEVEL=$LOG_LEVEL # this is set fix to false, because it is important for 'production' environments. only set to true if a graphql-playground should be in use From eb51fa8719761580048972d62802c3185c9af2b2 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 19:16:31 +0100 Subject: [PATCH 46/85] fix bug, add FEDERATION_XCOM_SENDCOINS_ENABLED to deployment script --- backend/.env.template | 1 + deployment/bare_metal/.env.dist | 3 +++ dht-node/.env.template | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/.env.template b/backend/.env.template index 1cf7d9dee..5165dcef3 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -62,3 +62,4 @@ WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET # Federation FEDERATION_VALIDATE_COMMUNITY_TIMER=$FEDERATION_VALIDATE_COMMUNITY_TIMER +FEDERATION_XCOM_SENDCOINS_ENABLED=$FEDERATION_XCOM_SENDCOINS_ENABLED \ No newline at end of file diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 96df6f81b..deba914b1 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -12,6 +12,9 @@ EMAIL_PASSWORD=1234 EMAIL_SMTP_URL=smtp.lustig.de EMAIL_SMTP_PORT=587 +# if set to true allow sending gradidos to another communities +FEDERATION_XCOM_SENDCOINS_ENABLED=false + # how many minutes email verification code is valid # also used for password reset code EMAIL_CODE_VALID_TIME=1440 diff --git a/dht-node/.env.template b/dht-node/.env.template index 629aaf069..b4cef7f5e 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -19,7 +19,6 @@ FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # on an hash created from this topic FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED -FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL # comma separated values, which apis should be announced FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS COMMUNITY_HOST=$COMMUNITY_HOST From 3e32726fa103262cd2a8af0335996a48b8587165 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:00:14 +0100 Subject: [PATCH 47/85] give infos for exceptions --- backend/.env.dist | 3 ++- backend/src/federation/client/1_0/FederationClient.ts | 10 ++++++++-- federation/src/client/1_0/AuthenticationClient.ts | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 96afd1ab5..82f489f6c 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -62,4 +62,5 @@ WEBHOOK_ELOPAGE_SECRET=secret # LOG_LEVEL=info # Federation -FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 \ No newline at end of file +FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 +FEDERATION_XCOM_SENDCOINS_ENABLED=false \ No newline at end of file diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 4a10ddc7e..8fd7744e7 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -46,7 +46,10 @@ export class FederationClient { ) return data.getPublicKey.publicKey } catch (err) { - logger.warn('Federation: getPublicKey failed for endpoint', this.endpoint) + logger.warn('Federation: getPublicKey failed for endpoint', { + endpoint: this.endpoint, + err, + }) } } @@ -71,7 +74,10 @@ export class FederationClient { ) return data.getPublicCommunityInfo } catch (err) { - logger.warn('Federation: getPublicCommunityInfo failed for endpoint', this.endpoint) + logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { + endpoint: this.endpoint, + err, + }) } } } diff --git a/federation/src/client/1_0/AuthenticationClient.ts b/federation/src/client/1_0/AuthenticationClient.ts index bed6b88c4..3a94746b1 100644 --- a/federation/src/client/1_0/AuthenticationClient.ts +++ b/federation/src/client/1_0/AuthenticationClient.ts @@ -63,7 +63,10 @@ export class AuthenticationClient { return authUuid } } catch (err) { - logger.error('Authentication: authenticate failed for endpoint', this.endpoint) + logger.error('Authentication: authenticate failed', { + endpoint: this.endpoint, + err, + }) } return null } From eaa4161d14637fc2e7277eb2a8283ea5fe0b5a6e Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:10:46 +0100 Subject: [PATCH 48/85] fix problem with lost update --- .../federation/client/1_0/FederationClient.ts | 4 ++++ .../client/FederationClientFactory.ts | 20 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 8fd7744e7..e3df5ecf8 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -28,6 +28,10 @@ export class FederationClient { }) } + getEndpoint = () => { + return this.endpoint + } + getPublicKey = async (): Promise => { logger.debug('Federation: getPublicKey from endpoint', this.endpoint) try { diff --git a/backend/src/federation/client/FederationClientFactory.ts b/backend/src/federation/client/FederationClientFactory.ts index d057ffd04..fe2ff0dbd 100644 --- a/backend/src/federation/client/FederationClientFactory.ts +++ b/backend/src/federation/client/FederationClientFactory.ts @@ -47,15 +47,25 @@ export class FederationClientFactory { const instance = FederationClientFactory.instanceArray.find( (instance) => instance.id === dbCom.id, ) - if (instance) { + // TODO: found a way to prevent double code with FederationClient::constructor + const endpoint = `${dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/'}${ + dbCom.apiVersion + }/` + // check if endpoint is still the same and not changed meanwhile + if (instance && instance.client.getEndpoint() === endpoint) { return instance.client } const client = FederationClientFactory.createFederationClient(dbCom) if (client) { - FederationClientFactory.instanceArray.push({ - id: dbCom.id, - client, - } as FederationClientInstance) + // only update instance if we already have one + if (instance) { + instance.client = client + } else { + FederationClientFactory.instanceArray.push({ + id: dbCom.id, + client, + } as FederationClientInstance) + } } return client } From 0640c8e371c03ab09d86ee6e9e01e12a5442341c Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:33:55 +0100 Subject: [PATCH 49/85] shorting result if response was a website --- backend/src/federation/client/1_0/FederationClient.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index e3df5ecf8..0b55c80a6 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -50,9 +50,10 @@ export class FederationClient { ) return data.getPublicKey.publicKey } catch (err) { + const errorString = JSON.stringify(err) logger.warn('Federation: getPublicKey failed for endpoint', { endpoint: this.endpoint, - err, + err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', }) } } @@ -78,9 +79,10 @@ export class FederationClient { ) return data.getPublicCommunityInfo } catch (err) { + const errorString = JSON.stringify(err) logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { endpoint: this.endpoint, - err, + err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', }) } } From c7d4997ecc7e49d4c22c32d0c39cbffc51ea9ec1 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 13:32:01 +0100 Subject: [PATCH 50/85] add nginx request limit within nginx config --- deployment/bare_metal/nginx/common/limit_requests.conf | 3 +++ .../sites-available/gradido-federation.conf.template | 2 ++ .../nginx/sites-available/gradido.conf.ssl.template | 6 ++++++ .../nginx/sites-available/gradido.conf.template | 9 +++++++-- .../nginx/sites-available/update-page.conf.ssl.template | 2 ++ .../nginx/sites-available/update-page.conf.template | 2 ++ 6 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 deployment/bare_metal/nginx/common/limit_requests.conf diff --git a/deployment/bare_metal/nginx/common/limit_requests.conf b/deployment/bare_metal/nginx/common/limit_requests.conf new file mode 100644 index 000000000..e9026ee81 --- /dev/null +++ b/deployment/bare_metal/nginx/common/limit_requests.conf @@ -0,0 +1,3 @@ +limit_req_zone $binary_remote_addr zone=frontend:20m rate=5r/s; +limit_req_zone $binary_remote_addr zone=backend:25m rate=15r/s; +limit_req_zone $binary_remote_addr zone=api:5m rate=30r/s; \ No newline at end of file diff --git a/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template b/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template index 2192b7dbb..1148cc9f7 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template @@ -1,5 +1,7 @@ location /api/$FEDERATION_APIVERSION { + limit_req zone=api burst=60 nodelay; + proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index b8559a0fb..b130d7374 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -21,6 +21,7 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; + include /etc/nginx/common/limit_requests.conf; #gzip_static on; gzip on; @@ -42,6 +43,7 @@ server { # Frontend (default) location / { + limit_req zone=frontend burst=40 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -58,6 +60,7 @@ server { # Backend location /graphql { + limit_req zone=backend burst=10 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -74,6 +77,7 @@ server { # Backend webhooks location /hook { + limit_req zone=backend burst=10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -90,6 +94,7 @@ server { # Webhook reverse proxy location /hooks/ { + limit_req zone=backend burst=10; proxy_pass http://127.0.0.1:9000/hooks/; access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; @@ -98,6 +103,7 @@ server { # Admin Frontend location /admin { + limit_req zone=frontend burst=30 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index 6b885a26a..91ab0d3bc 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -6,6 +6,7 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; + include /etc/nginx/common/limit_requests.conf; #gzip_static on; gzip on; @@ -27,6 +28,7 @@ server { # Frontend (default) location / { + limit_req zone=frontend burst=40 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -43,6 +45,7 @@ server { # Backend location /graphql { + limit_req zone=backend burst=10 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -59,6 +62,7 @@ server { # Backend webhooks location /hook { + limit_req zone=backend burst=10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -66,7 +70,6 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; - # no trailing slash to keep the hook/ prefix proxy_pass http://127.0.0.1:4000/hook; proxy_redirect off; @@ -76,6 +79,7 @@ server { # Webhook reverse proxy location /hooks/ { + limit_req zone=backend burst=10; proxy_pass http://127.0.0.1:9000/hooks/; access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; @@ -84,6 +88,7 @@ server { # Admin Frontend location /admin { + limit_req zone=frontend burst=30 nodelay; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -97,7 +102,7 @@ server { access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log; error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; } - + # Federation $FEDERATION_NGINX_CONF diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template index 06bc5bbc0..7d30cd273 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -21,6 +21,7 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; + include /etc/nginx/common/limit_requests.conf; gzip on; @@ -28,6 +29,7 @@ server { index updating.html; location / { + limit_req zone=frontend; try_files /updating.html =404; } diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.template index e6cb51c7c..6236d88b0 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.template @@ -6,6 +6,7 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; + include /etc/nginx/common/limit_requests.conf; gzip on; @@ -13,6 +14,7 @@ server { index updating.html; location / { + limit_req zone=frontend; try_files /updating.html =404; } From 842008c87121b0a155370e1c3b9f367f0df5ed3a Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 13:46:21 +0100 Subject: [PATCH 51/85] add helmet which will set https header for more security --- backend/package.json | 1 + backend/src/server/createServer.ts | 5 ++ backend/yarn.lock | 7 +- dlt-connector/package.json | 1 + dlt-connector/schema.graphql | 98 ++++++++++++++++++++++++ dlt-connector/src/server/createServer.ts | 4 + dlt-connector/yarn.lock | 5 ++ federation/package.json | 1 + federation/src/server/createServer.ts | 4 + federation/yarn.lock | 5 ++ 10 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 dlt-connector/schema.graphql diff --git a/backend/package.json b/backend/package.json index 45fe7b050..940af3ecb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -32,6 +32,7 @@ "gradido-database": "file:../database", "graphql": "^15.5.1", "graphql-request": "5.0.0", + "helmet": "^7.1.0", "i18n": "^0.15.1", "jose": "^4.14.4", "lodash.clonedeep": "^4.5.0", diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index c162d9f6f..e10b6cb5c 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -4,6 +4,7 @@ import { Connection as DbConnection } from '@dbTools/typeorm' import { ApolloServer } from 'apollo-server-express' import express, { Express, json, urlencoded } from 'express' +import helmet from 'helmet' import { Logger } from 'log4js' import { CONFIG } from '@/config' @@ -56,6 +57,10 @@ export const createServer = async ( // cors app.use(cors) + // Helmet helps secure Express apps by setting HTTP response headers. + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + app.use(helmet()) + // bodyparser json app.use(json()) // bodyparser urlencoded for elopage diff --git a/backend/yarn.lock b/backend/yarn.lock index 0b3ceb323..253bbb178 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -3679,7 +3679,7 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== "gradido-database@file:../database": - version "2.0.1" + version "2.1.1" dependencies: "@types/uuid" "^8.3.4" cross-env "^7.0.3" @@ -3826,6 +3826,11 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +helmet@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 5a4c54394..54a31669a 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -31,6 +31,7 @@ "express": "4.17.1", "graphql": "^16.7.1", "graphql-scalars": "^1.22.2", + "helmet": "^7.1.0", "log4js": "^6.7.1", "nodemon": "^2.0.20", "protobufjs": "^7.2.5", diff --git a/dlt-connector/schema.graphql b/dlt-connector/schema.graphql new file mode 100644 index 000000000..4ee07180d --- /dev/null +++ b/dlt-connector/schema.graphql @@ -0,0 +1,98 @@ +# ----------------------------------------------- +# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!! +# !!! DO NOT MODIFY THIS FILE BY YOURSELF !!! +# ----------------------------------------------- + +type Community { + confirmedAt: String! + createdAt: String! + foreign: Boolean! + id: Int! + iotaTopic: String! + rootPublicKeyHex: String! +} + +input CommunityDraft { + createdAt: String! + foreign: Boolean! + uuid: String! +} + +"""The `Decimal` scalar type to represent currency values""" +scalar Decimal + +"""Type of the transaction""" +enum InputTransactionType { + CREATION + RECEIVE + SEND +} + +type Mutation { + addCommunity(data: CommunityDraft!): TransactionResult! + sendTransaction(data: TransactionDraft!): TransactionResult! +} + +type Query { + communities(confirmed: Boolean, foreign: Boolean, uuid: String): [Community!]! + community(confirmed: Boolean, foreign: Boolean, uuid: String): Community! + isCommunityExist(confirmed: Boolean, foreign: Boolean, uuid: String): Boolean! +} + +input TransactionDraft { + amount: Decimal! + backendTransactionId: Int! + createdAt: String! + recipientUser: UserIdentifier! + senderUser: UserIdentifier! + targetDate: String + type: InputTransactionType! +} + +type TransactionError { + message: String! + name: String! + type: TransactionErrorType! +} + +"""Transaction Error Type""" +enum TransactionErrorType { + ALREADY_EXIST + DB_ERROR + INVALID_SIGNATURE + LOGIC_ERROR + MISSING_PARAMETER + NOT_FOUND + NOT_IMPLEMENTED_YET + PROTO_DECODE_ERROR + PROTO_ENCODE_ERROR +} + +type TransactionRecipe { + createdAt: String! + id: Int! + topic: String! + type: TransactionType! +} + +type TransactionResult { + error: TransactionError + recipe: TransactionRecipe + succeed: Boolean! +} + +"""Type of the transaction""" +enum TransactionType { + COMMUNITY_ROOT + GRADIDO_CREATION + GRADIDO_DEFERRED_TRANSFER + GRADIDO_TRANSFER + GROUP_FRIENDS_UPDATE + REGISTER_ADDRESS +} + +input UserIdentifier { + accountNr: Int = 1 + communityUuid: String + uuid: String! +} \ No newline at end of file diff --git a/dlt-connector/src/server/createServer.ts b/dlt-connector/src/server/createServer.ts index ed87d54ac..66b9f18b3 100755 --- a/dlt-connector/src/server/createServer.ts +++ b/dlt-connector/src/server/createServer.ts @@ -6,6 +6,7 @@ import bodyParser from 'body-parser' import cors from 'cors' import express, { Express } from 'express' // graphql +import helmet from 'helmet' import { Logger } from 'log4js' import { schema } from '@/graphql/schema' @@ -40,6 +41,9 @@ const createServer = async ( // plugins logger, }) + // Helmet helps secure Express apps by setting HTTP response headers. + app.use(helmet()) + await apollo.start() app.use( '/', diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index 3c7a8bf36..e4a057dd5 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -3407,6 +3407,11 @@ hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +helmet@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" diff --git a/federation/package.json b/federation/package.json index fa21e04a1..0b2809754 100644 --- a/federation/package.json +++ b/federation/package.json @@ -26,6 +26,7 @@ "express": "4.17.1", "graphql": "15.5.1", "graphql-request": "5.0.0", + "helmet": "^7.1.0", "lodash.clonedeep": "^4.5.0", "log4js": "^6.7.1", "reflect-metadata": "^0.1.13", diff --git a/federation/src/server/createServer.ts b/federation/src/server/createServer.ts index b79847254..3a75f6764 100644 --- a/federation/src/server/createServer.ts +++ b/federation/src/server/createServer.ts @@ -24,6 +24,7 @@ import { Connection } from '@dbTools/typeorm' import { apolloLogger } from './logger' import { Logger } from 'log4js' +import helmet from 'helmet' // i18n // import { i18n } from './localization' @@ -62,6 +63,9 @@ export const createServer = async ( // cors app.use(cors) + // Helmet helps secure Express apps by setting HTTP response headers. + app.use(helmet()) + // bodyparser json app.use(express.json()) // bodyparser urlencoded for elopage diff --git a/federation/yarn.lock b/federation/yarn.lock index ca33138dd..7a9ec6814 100644 --- a/federation/yarn.lock +++ b/federation/yarn.lock @@ -3127,6 +3127,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helmet@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" From 3e51511b2a64b85f542addb57fb081b655d97850 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 14:11:40 +0100 Subject: [PATCH 52/85] add rate limiter on node server level --- backend/package.json | 1 + backend/src/server/createServer.ts | 19 +++++++++++++++++++ backend/yarn.lock | 12 ++++++++++++ dlt-connector/package.json | 1 + dlt-connector/src/server/createServer.ts | 19 +++++++++++++++++++ dlt-connector/yarn.lock | 12 ++++++++++++ federation/package.json | 1 + federation/src/server/createServer.ts | 19 +++++++++++++++++++ federation/yarn.lock | 12 ++++++++++++ 9 files changed, 96 insertions(+) diff --git a/backend/package.json b/backend/package.json index 940af3ecb..9f5e7e644 100644 --- a/backend/package.json +++ b/backend/package.json @@ -29,6 +29,7 @@ "dotenv": "^10.0.0", "email-templates": "^10.0.1", "express": "^4.17.1", + "express-slow-down": "^2.0.1", "gradido-database": "file:../database", "graphql": "^15.5.1", "graphql-request": "5.0.0", diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index e10b6cb5c..250a4b901 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -4,6 +4,7 @@ import { Connection as DbConnection } from '@dbTools/typeorm' import { ApolloServer } from 'apollo-server-express' import express, { Express, json, urlencoded } from 'express' +import { slowDown } from 'express-slow-down' import helmet from 'helmet' import { Logger } from 'log4js' @@ -61,6 +62,24 @@ export const createServer = async ( // eslint-disable-next-line @typescript-eslint/no-unsafe-call app.use(helmet()) + // rate limiter/ slow down to many requests + const limiter = slowDown({ + windowMs: 1000, // 1 second + delayAfter: 10, // Allow 10 requests per 1 second. + delayMs: (hits) => hits * 50, // Add 100 ms of delay to every request after the 10th one. + /** + * So: + * + * - requests 1-10 are not delayed. + * - request 11 is delayed by 550ms + * - request 12 is delayed by 600ms + * - request 13 is delayed by 650ms + * + * and so on. After 1 seconds, the delay is reset to 0. + */ + }) + app.use(limiter) + // bodyparser json app.use(json()) // bodyparser urlencoded for elopage diff --git a/backend/yarn.lock b/backend/yarn.lock index 253bbb178..4b4822a2d 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -3225,6 +3225,18 @@ expect@^27.2.5: jest-message-util "^27.2.5" jest-regex-util "^27.0.6" +express-rate-limit@7: + version "7.1.5" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.5.tgz#af4c81143a945ea97f2599d13957440a0ddbfcfe" + integrity sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw== + +express-slow-down@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-2.0.1.tgz#60c4515467314675d89c54ec608e2d586aa30f87" + integrity sha512-zRogSZhNXJYKDBekhgFfFXGrOngH7Fub7Mx2g8OQ4RUBwSJP/3TVEKMgSGR/WlneT0mJ6NBUnidHhIELGVPe3w== + dependencies: + express-rate-limit "7" + express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 54a31669a..8b5ae357c 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -29,6 +29,7 @@ "dlt-database": "file:../dlt-database", "dotenv": "10.0.0", "express": "4.17.1", + "express-slow-down": "^2.0.1", "graphql": "^16.7.1", "graphql-scalars": "^1.22.2", "helmet": "^7.1.0", diff --git a/dlt-connector/src/server/createServer.ts b/dlt-connector/src/server/createServer.ts index 66b9f18b3..50e8d96cb 100755 --- a/dlt-connector/src/server/createServer.ts +++ b/dlt-connector/src/server/createServer.ts @@ -6,6 +6,7 @@ import bodyParser from 'body-parser' import cors from 'cors' import express, { Express } from 'express' // graphql +import { slowDown } from 'express-slow-down' import helmet from 'helmet' import { Logger } from 'log4js' @@ -44,6 +45,24 @@ const createServer = async ( // Helmet helps secure Express apps by setting HTTP response headers. app.use(helmet()) + // rate limiter/ slow down to many requests + const limiter = slowDown({ + windowMs: 1000, // 1 second + delayAfter: 10, // Allow 10 requests per 1 second. + delayMs: (hits) => hits * 50, // Add 100 ms of delay to every request after the 10th one. + /** + * So: + * + * - requests 1-10 are not delayed. + * - request 11 is delayed by 550ms + * - request 12 is delayed by 600ms + * - request 13 is delayed by 650ms + * + * and so on. After 1 seconds, the delay is reset to 0. + */ + }) + app.use(limiter) + await apollo.start() app.use( '/', diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index e4a057dd5..6d50426b1 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -2833,6 +2833,18 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +express-rate-limit@7: + version "7.1.5" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.5.tgz#af4c81143a945ea97f2599d13957440a0ddbfcfe" + integrity sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw== + +express-slow-down@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-2.0.1.tgz#60c4515467314675d89c54ec608e2d586aa30f87" + integrity sha512-zRogSZhNXJYKDBekhgFfFXGrOngH7Fub7Mx2g8OQ4RUBwSJP/3TVEKMgSGR/WlneT0mJ6NBUnidHhIELGVPe3w== + dependencies: + express-rate-limit "7" + express@4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" diff --git a/federation/package.json b/federation/package.json index 0b2809754..1457b1be1 100644 --- a/federation/package.json +++ b/federation/package.json @@ -24,6 +24,7 @@ "decimal.js-light": "^2.5.1", "dotenv": "10.0.0", "express": "4.17.1", + "express-slow-down": "^2.0.1", "graphql": "15.5.1", "graphql-request": "5.0.0", "helmet": "^7.1.0", diff --git a/federation/src/server/createServer.ts b/federation/src/server/createServer.ts index 3a75f6764..97729b882 100644 --- a/federation/src/server/createServer.ts +++ b/federation/src/server/createServer.ts @@ -25,6 +25,7 @@ import { Connection } from '@dbTools/typeorm' import { apolloLogger } from './logger' import { Logger } from 'log4js' import helmet from 'helmet' +import { slowDown } from 'express-slow-down' // i18n // import { i18n } from './localization' @@ -66,6 +67,24 @@ export const createServer = async ( // Helmet helps secure Express apps by setting HTTP response headers. app.use(helmet()) + // rate limiter/ slow down to many requests + const limiter = slowDown({ + windowMs: 1000, // 1 second + delayAfter: 10, // Allow 10 requests per 1 second. + delayMs: (hits) => hits * 50, // Add 100 ms of delay to every request after the 10th one. + /** + * So: + * + * - requests 1-10 are not delayed. + * - request 11 is delayed by 550ms + * - request 12 is delayed by 600ms + * - request 13 is delayed by 650ms + * + * and so on. After 1 seconds, the delay is reset to 0. + */ + }) + app.use(limiter) + // bodyparser json app.use(express.json()) // bodyparser urlencoded for elopage diff --git a/federation/yarn.lock b/federation/yarn.lock index 7a9ec6814..74cc04521 100644 --- a/federation/yarn.lock +++ b/federation/yarn.lock @@ -2624,6 +2624,18 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +express-rate-limit@7: + version "7.1.5" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.5.tgz#af4c81143a945ea97f2599d13957440a0ddbfcfe" + integrity sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw== + +express-slow-down@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-2.0.1.tgz#60c4515467314675d89c54ec608e2d586aa30f87" + integrity sha512-zRogSZhNXJYKDBekhgFfFXGrOngH7Fub7Mx2g8OQ4RUBwSJP/3TVEKMgSGR/WlneT0mJ6NBUnidHhIELGVPe3w== + dependencies: + express-rate-limit "7" + express@4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" From 1c4ab74bbfbe7fd2be41c1ad8212a0f7bb9e2e6e Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 14:26:55 +0100 Subject: [PATCH 53/85] use older version because 7 isn't working with backend at all, https://github.com/helmetjs/helmet/issues/424 --- backend/package.json | 2 +- backend/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/package.json b/backend/package.json index 9f5e7e644..7a27b1c43 100644 --- a/backend/package.json +++ b/backend/package.json @@ -33,7 +33,7 @@ "gradido-database": "file:../database", "graphql": "^15.5.1", "graphql-request": "5.0.0", - "helmet": "^7.1.0", + "helmet": "^6.2.0", "i18n": "^0.15.1", "jose": "^4.14.4", "lodash.clonedeep": "^4.5.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index 4b4822a2d..ffda08949 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -3838,10 +3838,10 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -helmet@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" - integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== +helmet@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-6.2.0.tgz#c29d62014be4c70b8ef092c9c5e54c8c26b8e16e" + integrity sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg== highlight.js@^10.7.1: version "10.7.3" From b63faab3fb855e80708ac9979e8da21b393a0674 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 16:51:19 +0100 Subject: [PATCH 54/85] ent --- backend/package.json | 2 +- backend/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/package.json b/backend/package.json index 7a27b1c43..43b7fb87c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -33,7 +33,7 @@ "gradido-database": "file:../database", "graphql": "^15.5.1", "graphql-request": "5.0.0", - "helmet": "^6.2.0", + "helmet": "^5.1.1", "i18n": "^0.15.1", "jose": "^4.14.4", "lodash.clonedeep": "^4.5.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index ffda08949..234dc817a 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -3838,10 +3838,10 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -helmet@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-6.2.0.tgz#c29d62014be4c70b8ef092c9c5e54c8c26b8e16e" - integrity sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg== +helmet@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-5.1.1.tgz#609823c5c2e78aea62dd9afc8f544ca409da5e85" + integrity sha512-/yX0oVZBggA9cLJh8aw3PPCfedBnbd7J2aowjzsaWwZh7/UFY0nccn/aHAggIgWUFfnykX8GKd3a1pSbrmlcVQ== highlight.js@^10.7.1: version "10.7.3" From 5fc176de0bcd97d64aea48f63036eac80c037517 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 17:35:47 +0100 Subject: [PATCH 55/85] protection for slow lowris and range attack --- .../gradido-federation.conf.template | 1 + .../sites-available/gradido.conf.ssl.template | 14 ++++++++++++++ .../nginx/sites-available/gradido.conf.template | 14 ++++++++++++++ .../sites-available/update-page.conf.ssl.template | 10 ++++++++++ .../sites-available/update-page.conf.template | 10 ++++++++++ 5 files changed, 49 insertions(+) diff --git a/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template b/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template index 1148cc9f7..5123deb5e 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido-federation.conf.template @@ -1,6 +1,7 @@ location /api/$FEDERATION_APIVERSION { limit_req zone=api burst=60 nodelay; + limit_conn addr 30; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index b130d7374..822c326d0 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -23,6 +23,15 @@ server { include /etc/nginx/common/protect_add_header.conf; include /etc/nginx/common/limit_requests.conf; + # protect from slow loris + client_body_timeout 10s; + client_header_timeout 10s; + + # protect from range attack (in http header) + if ($http_range ~ "d{9,}") { + return 444; + } + #gzip_static on; gzip on; gzip_proxied any; @@ -44,6 +53,7 @@ server { # Frontend (default) location / { limit_req zone=frontend burst=40 nodelay; + limit_conn addr 40; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -61,6 +71,7 @@ server { # Backend location /graphql { limit_req zone=backend burst=10 nodelay; + limit_conn addr 10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -78,6 +89,7 @@ server { # Backend webhooks location /hook { limit_req zone=backend burst=10; + limit_conn addr 10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -95,6 +107,7 @@ server { # Webhook reverse proxy location /hooks/ { limit_req zone=backend burst=10; + limit_conn addr 10; proxy_pass http://127.0.0.1:9000/hooks/; access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; @@ -104,6 +117,7 @@ server { # Admin Frontend location /admin { limit_req zone=frontend burst=30 nodelay; + limit_conn addr 40; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index 91ab0d3bc..1f673ee41 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -8,6 +8,15 @@ server { include /etc/nginx/common/protect_add_header.conf; include /etc/nginx/common/limit_requests.conf; + # protect from slow loris + client_body_timeout 10s; + client_header_timeout 10s; + + # protect from range attack (in http header) + if ($http_range ~ "d{9,}") { + return 444; + } + #gzip_static on; gzip on; gzip_proxied any; @@ -29,6 +38,7 @@ server { # Frontend (default) location / { limit_req zone=frontend burst=40 nodelay; + limit_conn addr 40; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -46,6 +56,7 @@ server { # Backend location /graphql { limit_req zone=backend burst=10 nodelay; + limit_conn addr 10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -63,6 +74,7 @@ server { # Backend webhooks location /hook { limit_req zone=backend burst=10; + limit_conn addr 10; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -80,6 +92,7 @@ server { # Webhook reverse proxy location /hooks/ { limit_req zone=backend burst=10; + limit_conn addr 10; proxy_pass http://127.0.0.1:9000/hooks/; access_log $GRADIDO_LOG_PATH/nginx-access.hooks.log gradido_log; @@ -89,6 +102,7 @@ server { # Admin Frontend location /admin { limit_req zone=frontend burst=30 nodelay; + limit_conn addr 40; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template index 7d30cd273..ee7732230 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -23,6 +23,15 @@ server { include /etc/nginx/common/protect_add_header.conf; include /etc/nginx/common/limit_requests.conf; + # protect from slow loris + client_body_timeout 10s; + client_header_timeout 10s; + + # protect from range attack (in http header) + if ($http_range ~ "d{9,}") { + return 444; + } + gzip on; root $NGINX_UPDATE_PAGE_ROOT; @@ -30,6 +39,7 @@ server { location / { limit_req zone=frontend; + limit_conn addr 10; try_files /updating.html =404; } diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.template index 6236d88b0..38dfb2d02 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.template @@ -8,6 +8,15 @@ server { include /etc/nginx/common/protect_add_header.conf; include /etc/nginx/common/limit_requests.conf; + # protect from slow loris + client_body_timeout 10s; + client_header_timeout 10s; + + # protect from range attack (in http header) + if ($http_range ~ "d{9,}") { + return 444; + } + gzip on; root $NGINX_UPDATE_PAGE_ROOT; @@ -15,6 +24,7 @@ server { location / { limit_req zone=frontend; + limit_conn addr 10; try_files /updating.html =404; } From ac0244ade0be604d592e691cb3f324a21a26d996 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 23 Jan 2024 11:35:22 +0100 Subject: [PATCH 56/85] change condition to 200 --- backend/src/federation/client/1_0/FederationClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 0b55c80a6..b9939a12c 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -53,7 +53,7 @@ export class FederationClient { const errorString = JSON.stringify(err) logger.warn('Federation: getPublicKey failed for endpoint', { endpoint: this.endpoint, - err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', + err: errorString.length <= 200 ? errorString : errorString.substring(0, 200) + '...', }) } } @@ -82,7 +82,7 @@ export class FederationClient { const errorString = JSON.stringify(err) logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { endpoint: this.endpoint, - err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', + err: errorString.length <= 200 ? errorString : errorString.substring(0, 200) + '...', }) } } From 50ebcbb57b183da27a166e2f4b94bfd11bdfacd7 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 23 Jan 2024 12:11:05 +0100 Subject: [PATCH 57/85] improve tests --- .../resolver/CommunityResolver.test.ts | 154 +++++++++--------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 4f42e9455..e0cdc06fa 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -34,6 +34,60 @@ afterAll(async () => { await con.close() }) +// real valid ed25519 key pairs +const ed25519KeyPairStaticHex = [ + { + public: '264c1e88914d18166cc31e8d6c2111c03ac83f5910398eb45cd425c6c3836367', + private: + '0ddcafd5e2da92e171ccc974af22fee3ad8407475e330586c8f259837d4fedc6264c1e88914d18166cc31e8d6c2111c03ac83f5910398eb45cd425c6c3836367', + }, + { + public: 'ac18a8754f725079f93d27b9054f2eff536109a2fd439f9755941abdd639baf0', + private: + '45325a0d0f22655095321d9d05999c65245da02130318ff51da1ee423b836117ac18a8754f725079f93d27b9054f2eff536109a2fd439f9755941abdd639baf0', + }, + { + public: '6f7d4ccde610db1e1a33fabbb444d5400013c168296b03fd50bc686d4c1ad0ed', + private: + '8ab6d5da8b666ef5b3d754559c028806a1e2f8142a3e7ada411a8b6a3fe70eeb6f7d4ccde610db1e1a33fabbb444d5400013c168296b03fd50bc686d4c1ad0ed', + }, + { + public: '85fbbce0763db24677cf7cb579a743013557a4fea0a9a624245f3ae8cd785e1d', + private: + '0369ea7c80c3134c2872c3cf77a68f12d57de57359145b550e3a0c4c8170a31785fbbce0763db24677cf7cb579a743013557a4fea0a9a624245f3ae8cd785e1d', + }, + { + public: 'b099d023476ece01f231c269cbe496139ca73b3b4eb705816a511a1ca09661d0', + private: + '015ac650157b9e9bdbe718940606242daa318a251e8417b49440495e5afe3750b099d023476ece01f231c269cbe496139ca73b3b4eb705816a511a1ca09661d0', + }, + { + public: '9f8dc17f1af9f71e9b9a1cd49ca295b89049863515a487578ad4f90b307abf39', + private: + '0c13e71c55a3c03bd5df05c92bbccde88ad4a47f3bac6bdc5383ef1ec946cfdc9f8dc17f1af9f71e9b9a1cd49ca295b89049863515a487578ad4f90b307abf39', + }, + { + public: '34218b2f570d341370dd2db111d0ef2415c03a110c3bf3127c6b2337af71753a', + private: + '60f3479bba44d035886ac21c362bceece9f9ec81859c9b37f734b6442a06c93b34218b2f570d341370dd2db111d0ef2415c03a110c3bf3127c6b2337af71753a', + }, + { + public: 'a447404f5e04ed4896ed64d0f704574ed780b52e90868d4b83e1afb8ea687ff6', + private: + 'ea85ebb4332a52d87fe6f322dcd23ad4afc5eafb93dfff2216f3ffa9f0730e8aa447404f5e04ed4896ed64d0f704574ed780b52e90868d4b83e1afb8ea687ff6', + }, + { + public: 'b8b987c55da62b30d929672520551033eb37abdd88f9ea104db5d107c19680b4', + private: + '29475dbbc96d694b3c653a1e143caf084f6daf2d35267522c4096c55b47e2b76b8b987c55da62b30d929672520551033eb37abdd88f9ea104db5d107c19680b4', + }, + { + public: '40203d18a6ff8fb3c4c62d78e4807036fc9207782ce97a9bcf3be0755c236c37', + private: + '0b5c4d536d222e88b561ea495e15918fb8cba61a3f8c261ec9e587cca560804040203d18a6ff8fb3c4c62d78e4807036fc9207782ce97a9bcf3be0755c236c37', + }, +] + describe('CommunityResolver', () => { describe('getCommunities', () => { let homeCom1: DbFederatedCommunity @@ -62,10 +116,7 @@ describe('CommunityResolver', () => { homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') homeCom1.apiVersion = '1_0' homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() @@ -73,10 +124,7 @@ describe('CommunityResolver', () => { homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false - homeCom2.publicKey = Buffer.from( - '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', - 'hex', - ) + homeCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[1].public, 'hex') homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() @@ -84,10 +132,7 @@ describe('CommunityResolver', () => { homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false - homeCom3.publicKey = Buffer.from( - '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', - 'hex', - ) + homeCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[2].public, 'hex') homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() @@ -101,9 +146,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching( - '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -114,9 +157,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching( - '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -127,9 +168,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -149,10 +188,7 @@ describe('CommunityResolver', () => { foreignCom1 = DbFederatedCommunity.create() foreignCom1.foreign = true - foreignCom1.publicKey = Buffer.from( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - 'hex', - ) + foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') foreignCom1.apiVersion = '1_0' foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() @@ -160,10 +196,7 @@ describe('CommunityResolver', () => { foreignCom2 = DbFederatedCommunity.create() foreignCom2.foreign = true - foreignCom2.publicKey = Buffer.from( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - 'hex', - ) + foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') foreignCom2.apiVersion = '1_1' foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() @@ -171,10 +204,7 @@ describe('CommunityResolver', () => { foreignCom3 = DbFederatedCommunity.create() foreignCom3.foreign = true - foreignCom3.publicKey = Buffer.from( - '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', - 'hex', - ) + foreignCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[5].public, 'hex') foreignCom3.apiVersion = '1_2' foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() @@ -188,7 +218,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching(homeCom3.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -199,7 +229,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching(homeCom2.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -210,7 +240,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching(homeCom1.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -221,9 +251,7 @@ describe('CommunityResolver', () => { { id: 6, foreign: foreignCom3.foreign, - publicKey: expect.stringMatching( - '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[5].public), url: expect.stringMatching('http://remotehost/api/1_2'), lastAnnouncedAt: null, verifiedAt: null, @@ -234,9 +262,7 @@ describe('CommunityResolver', () => { { id: 5, foreign: foreignCom2.foreign, - publicKey: expect.stringMatching( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[4].public), url: expect.stringMatching('http://remotehost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -247,9 +273,7 @@ describe('CommunityResolver', () => { { id: 4, foreign: foreignCom1.foreign, - publicKey: expect.stringMatching( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[3].public), url: expect.stringMatching('http://remotehost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -294,14 +318,8 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) - homeCom1.privateKey = Buffer.from( - 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') + homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -338,14 +356,8 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) - homeCom1.privateKey = Buffer.from( - 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') + homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -356,14 +368,8 @@ describe('CommunityResolver', () => { foreignCom1 = DbCommunity.create() foreignCom1.foreign = true foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - 'hex', - ) - foreignCom1.privateKey = Buffer.from( - 'd967220052995169b20b89a0c6190ee8aa9ca501d7a6df81c49a97003edca2ed724d69eaf55e62290d699d7c3ec8b44985fffd57def98d51b2202f2bd82330b3', - 'hex', - ) + foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') + foreignCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[3].private, 'hex') // foreignCom1.communityUuid = 'Stage2-Com-UUID' // foreignCom1.authenticatedAt = new Date() foreignCom1.name = 'Stage-2_Community-name' @@ -374,14 +380,8 @@ describe('CommunityResolver', () => { foreignCom2 = DbCommunity.create() foreignCom2.foreign = true foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - 'hex', - ) - foreignCom2.privateKey = Buffer.from( - '0ae8921a204bd27e1ba834ffa2f4480cca867b4def783934f3032e19c54d6e7c9fb3233eff07a0086f6bd8486e7220136ce941abdd51d268bfaca0cc3181f162', - 'hex', - ) + foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') + foreignCom2.privateKey = Buffer.from(ed25519KeyPairStaticHex[4].private, 'hex') foreignCom2.communityUuid = 'Stage3-Com-UUID' foreignCom2.authenticatedAt = new Date() foreignCom2.name = 'Stage-3_Community-name' From f875214eff6b7a76cc47b61ccc25e5738f4b4ab3 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Tue, 23 Jan 2024 22:07:47 +0100 Subject: [PATCH 58/85] test for updateUserInfo with geolocation but db-driver error --- .../src/graphql/arg/UpdateUserInfosArgs.ts | 11 +- backend/src/graphql/model/Location.ts | 23 +--- .../src/graphql/resolver/UserResolver.test.ts | 91 ++++++++++++++ backend/src/graphql/resolver/UserResolver.ts | 113 ++++++++++-------- backend/src/graphql/validator/Location.ts | 31 +++++ 5 files changed, 195 insertions(+), 74 deletions(-) create mode 100644 backend/src/graphql/validator/Location.ts diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index ab1263eee..40e63f488 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -1,8 +1,13 @@ -import { IsBoolean, IsInt, IsObject, IsString } from 'class-validator' -import { ArgsType, Field, Int } from 'type-graphql' +import { IsBoolean, IsInt, IsString } from 'class-validator' +import { ArgsType, Field, InputType, Int } from 'type-graphql' import { Location } from '@model/Location' +import { isValidLocation } from '../validator/Location' + +// import { isValidLocation } from '../validator/Location' + +@InputType() @ArgsType() export class UpdateUserInfosArgs { @Field({ nullable: true }) @@ -50,7 +55,7 @@ export class UpdateUserInfosArgs { gmsPublishName: number @Field(() => Location, { nullable: true }) - @IsObject() + @isValidLocation() gmsLocation?: Location | null @Field(() => Int, { nullable: false }) diff --git a/backend/src/graphql/model/Location.ts b/backend/src/graphql/model/Location.ts index 281ee9ff4..2b4c720f4 100644 --- a/backend/src/graphql/model/Location.ts +++ b/backend/src/graphql/model/Location.ts @@ -1,31 +1,10 @@ -import { Point } from '@dbTools/typeorm' -import { ArgsType, Field, InputType, Int } from 'type-graphql' +import { ArgsType, Field, Int } from 'type-graphql' -@InputType() @ArgsType() -// @ObjectType() export class Location { - constructor(lon: number, lat: number) { - this.longitude = lon - this.latitude = lat - } - @Field(() => Int) longitude: number @Field(() => Int) latitude: number - - // point is no Field and not part of the graphql type - private point: Point - - public getPoint(): Point { - const pointStr = '{ "type": "Point", "coordinates": [' - .concat(this.longitude.toString()) - .concat(', ') - .concat(this.latitude.toString()) - .concat('] }') - this.point = JSON.parse(pointStr) as Point - return this.point - } } diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 7a81b7017..f58cb53b0 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -23,6 +23,7 @@ import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { RoleNames } from '@enum/RoleNames' import { UserContactType } from '@enum/UserContactType' import { ContributionLink } from '@model/ContributionLink' +import { Location } from '@model/Location' import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' @@ -1237,6 +1238,9 @@ describe('UserResolver', () => { firstName: 'Benjamin', lastName: 'Blümchen', language: 'en', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }), ]) }) @@ -1275,6 +1279,93 @@ describe('UserResolver', () => { await expect(User.find()).resolves.toEqual([ expect.objectContaining({ alias: 'bibi_Bloxberg', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }), + ]) + }) + }) + }) + + describe('gms attributes', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + describe('default settings', () => { + it('updates the user in DB', async () => { + await mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }) + await expect(User.find()).resolves.toEqual([ + expect.objectContaining({ + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }), + ]) + }) + }) + + describe('individual settings', () => { + it('updates the user in DB', async () => { + await mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: false, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE, + }, + }) + await expect(User.find()).resolves.toEqual([ + expect.objectContaining({ + gmsAllowed: false, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE, + }), + ]) + }) + }) + + describe.only('with gms location', () => { + const loc = new Location() + loc.longitude = 9.573224 + loc.latitude = 49.679437 + console.log('with gms location:', loc) + it('updates the user in DB', async () => { + const usr = await User.find() + console.log('usr=', usr) + await mutate({ + mutation: updateUserInfos, + variables: { + /* + firstName: usr[0].firstName, + lastName: usr[0].lastName, + alias: usr[0].alias, + language: usr[0].language, + password: usr[0].password, + passwordNew: usr[0].password, + hideAmountGDD: usr[0].hideAmountGDD, + hideAmountGDT: usr[0].hideAmountGDT, + */ + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsLocation: loc, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }) + await expect(User.find()).resolves.toEqual([ + expect.objectContaining({ + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + location: loc, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }), ]) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index fa00a4d57..757ddd5d3 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -24,6 +24,7 @@ import { Order } from '@enum/Order' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserContactType } from '@enum/UserContactType' import { SearchAdminUsersResult } from '@model/AdminUser' +import { Location } from '@model/Location' import { User } from '@model/User' import { UserAdmin, SearchUsersResult } from '@model/UserAdmin' @@ -73,6 +74,7 @@ import { getKlicktippState } from './util/getKlicktippState' import { setUserRole, deleteUserRole } from './util/modifyUserRole' import { sendUserToGms } from './util/sendUserToGms' import { validateAlias } from './util/validateAlias' +import { Location2Point } from './util/Location2Point' const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] const DEFAULT_LANGUAGE = 'de' @@ -554,75 +556,88 @@ export class UserResolver { }: UpdateUserInfosArgs, @Ctx() context: Context, ): Promise { + console.log( + `updateUserInfos(${firstName}, ${lastName}, ${alias}, ${language}, ${password}, ${passwordNew}, ${hideAmountGDD}, ${hideAmountGDT}, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})`, + ) logger.info( - `updateUserInfos(${firstName}, ${lastName}, ${language}, ***, ***, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})...`, + `updateUserInfos(${firstName}, ${lastName}, ${alias}, ${language}, ***, ***, ${hideAmountGDD}, ${hideAmountGDT}, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})...`, ) const user = getUser(context) - - if (firstName) { - user.firstName = firstName - } - - if (lastName) { - user.lastName = lastName - } - - if (alias && (await validateAlias(alias))) { - user.alias = alias - } - - if (language) { - if (!isLanguage(language)) { - throw new LogError('Given language is not a valid language', language) - } - user.language = language - i18n.setLocale(language) - } - - if (password && passwordNew) { - // Validate Password - if (!isValidPassword(passwordNew)) { - throw new LogError( - 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', - ) + console.log('getUser:', user) + try { + if (firstName) { + user.firstName = firstName } - if (!verifyPassword(user, password)) { - throw new LogError(`Old password is invalid`) + if (lastName) { + user.lastName = lastName } - // Save new password hash and newly encrypted private key - user.passwordEncryptionType = PasswordEncryptionType.GRADIDO_ID - user.password = encryptPassword(user, passwordNew) - } + if (alias && (await validateAlias(alias))) { + user.alias = alias + } - // Save hideAmountGDD value - if (hideAmountGDD !== undefined) { - user.hideAmountGDD = hideAmountGDD - } - // Save hideAmountGDT value - if (hideAmountGDT !== undefined) { - user.hideAmountGDT = hideAmountGDT - } + if (language) { + if (!isLanguage(language)) { + throw new LogError('Given language is not a valid language', language) + } + user.language = language + i18n.setLocale(language) + } - user.gmsAllowed = gmsAllowed - user.gmsPublishName = gmsPublishName - if (gmsLocation) { - user.location = gmsLocation.getPoint() - } - user.gmsPublishLocation = gmsPublishLocation + if (password && passwordNew) { + // Validate Password + if (!isValidPassword(passwordNew)) { + throw new LogError( + 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', + ) + } + if (!verifyPassword(user, password)) { + throw new LogError(`Old password is invalid`) + } + + // Save new password hash and newly encrypted private key + user.passwordEncryptionType = PasswordEncryptionType.GRADIDO_ID + user.password = encryptPassword(user, passwordNew) + } + + // Save hideAmountGDD value + if (hideAmountGDD !== undefined) { + user.hideAmountGDD = hideAmountGDD + } + // Save hideAmountGDT value + if (hideAmountGDT !== undefined) { + user.hideAmountGDT = hideAmountGDT + } + + console.log('gmsAllowed:', user.gmsAllowed, gmsAllowed) + user.gmsAllowed = gmsAllowed + console.log('gmsPublishName:', user.gmsPublishName, gmsPublishName) + user.gmsPublishName = gmsPublishName + if (gmsLocation) { + console.log('1. gmsLocation:', user.location, gmsLocation) + user.location = Location2Point(gmsLocation) + console.log('2. gmsLocation:', user.location) + } + console.log('gmsPublishLocation:', user.gmsPublishLocation, gmsPublishLocation) + user.gmsPublishLocation = gmsPublishLocation + console.log('vor commit user:', user) + } catch (err) { + console.log('error:', err) + } const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') try { await queryRunner.manager.save(user).catch((error) => { + console.log('Error on saving user:', error) throw new LogError('Error saving user', error) }) await queryRunner.commitTransaction() - logger.debug('writing User data successful...') + logger.debug('writing User data successful...', user) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Error on writing updated user data', e) diff --git a/backend/src/graphql/validator/Location.ts b/backend/src/graphql/validator/Location.ts new file mode 100644 index 000000000..1333a626e --- /dev/null +++ b/backend/src/graphql/validator/Location.ts @@ -0,0 +1,31 @@ +import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator' + +import { Location } from '@model/Location' + +import { Location2Point } from '@/graphql/resolver/util/Location2Point' + +export function isValidLocation(validationOptions?: ValidationOptions) { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (object: Object, propertyName: string) { + registerDecorator({ + name: 'isValidLocation', + target: object.constructor, + propertyName, + options: validationOptions, + validator: { + validate(value: Location) { + // console.log('isValidLocation:', value, value.getPoint()) + if (!value || Location2Point(value).type === 'Point') { + console.log('isValidLocation: true') + return true + } + console.log('isValidLocation: false') + return false + }, + defaultMessage(args: ValidationArguments) { + return `${propertyName} must be a valid Location, ${args.property}` + }, + }, + }) + } +} From b2d2501f8976c8883420279090fd55f04b21ae42 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Tue, 23 Jan 2024 22:08:27 +0100 Subject: [PATCH 59/85] test for updateUserInfo with geolocation but with db-driver error --- .../graphql/resolver/util/Location2Point.ts | 32 +++++++++++++ backend/src/graphql/scalar/Geometry.ts | 33 ------------- backend/src/graphql/scalar/Location.ts | 46 +++++++++++++++++++ backend/src/graphql/scalar/Point.ts | 31 +++++++++++++ backend/src/graphql/schema.ts | 14 ++++-- 5 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 backend/src/graphql/resolver/util/Location2Point.ts delete mode 100644 backend/src/graphql/scalar/Geometry.ts create mode 100644 backend/src/graphql/scalar/Location.ts create mode 100644 backend/src/graphql/scalar/Point.ts diff --git a/backend/src/graphql/resolver/util/Location2Point.ts b/backend/src/graphql/resolver/util/Location2Point.ts new file mode 100644 index 000000000..c3849821d --- /dev/null +++ b/backend/src/graphql/resolver/util/Location2Point.ts @@ -0,0 +1,32 @@ +import { Point } from '@dbTools/typeorm' + +import { Location } from '@model/Location' + +export function Location2Point(location: Location): Point { + console.log('in Location2Point:', location) + let pointStr: string + if (location.longitude && location.latitude) { + pointStr = '{ "type": "Point", "coordinates": [' + .concat(location.longitude?.toString()) + .concat(', ') + .concat(location.latitude?.toString()) + .concat('] }') + } else { + pointStr = '{ "type": "Point", "coordinates": [] }' + } + console.log('pointStr:', pointStr) + const point = JSON.parse(pointStr) as Point + console.log('point:', point) + return point +} + +export function Point2Location(point: Point): Location { + console.log('in Point2Location:', point) + const location = new Location() + if (point.type === 'Point' && point.coordinates.length === 2) { + location.longitude = point.coordinates[0] + location.latitude = point.coordinates[1] + } + console.log('location:', location) + return location +} diff --git a/backend/src/graphql/scalar/Geometry.ts b/backend/src/graphql/scalar/Geometry.ts deleted file mode 100644 index c2cd48fdb..000000000 --- a/backend/src/graphql/scalar/Geometry.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { Geometry as DbGeometry } from '@dbTools/typeorm' -import { GraphQLScalarType, Kind } from 'graphql' - -import { Location } from '@model/Location' - -export const GeometryScalar = new GraphQLScalarType({ - name: 'Geometry', - description: - 'The `Geometry` scalar type to represent longitude and latitude values of a geo location', - - serialize(value: DbGeometry): Location { - // Check type of value - if (value.type !== 'Point') { - throw new Error(`GeometryScalar can only serialize Geometry type 'Point' values`) - } - - return new Location(value.coordinates[0], value.coordinates[1]) - }, - - parseValue(value): DbGeometry { - const geometry: DbGeometry = JSON.parse(value) as DbGeometry - return geometry - }, - - parseLiteral(ast) { - if (ast.kind !== Kind.STRING) { - throw new TypeError(`${String(ast)} is not a valid Geometry value.`) - } - - return JSON.parse(ast.value) as DbGeometry - }, -}) diff --git a/backend/src/graphql/scalar/Location.ts b/backend/src/graphql/scalar/Location.ts new file mode 100644 index 000000000..6002ee25b --- /dev/null +++ b/backend/src/graphql/scalar/Location.ts @@ -0,0 +1,46 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { GraphQLScalarType, Kind } from 'graphql' + +import { Location } from '@model/Location' + +export const LocationScalar = new GraphQLScalarType({ + name: 'Location', + description: + 'The `Location` scalar type to represent longitude and latitude values of a geo location', + + serialize(value: Location) { + console.log('serialize LocationScalar:', value) + return value + }, + + parseValue(value): Location { + console.log('parseValue LocationScalar:', value) + try { + const loc = new Location() + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + loc.longitude = value.longitude + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + loc.latitude = value.latitude + console.log('parsed:', loc) + return loc + } catch (err) { + console.log('Error:', err) + } + return new Location() + }, + + parseLiteral(ast): Location { + console.log('parseLiteral LocationScalar:', ast) + if (ast.kind !== Kind.STRING) { + throw new TypeError(`${String(ast)} is not a valid Location value.`) + } + let loc = new Location() + try { + loc = JSON.parse(ast.value) as Location + console.log('parsed:', loc) + } catch (err) { + console.log('Error:', err) + } + return loc + }, +}) diff --git a/backend/src/graphql/scalar/Point.ts b/backend/src/graphql/scalar/Point.ts new file mode 100644 index 000000000..06af56bfc --- /dev/null +++ b/backend/src/graphql/scalar/Point.ts @@ -0,0 +1,31 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { Point as DbPoint } from '@dbTools/typeorm' +import { GraphQLScalarType, Kind } from 'graphql' + +export const PointScalar = new GraphQLScalarType({ + name: 'Point', + description: + 'The `Point` scalar type to represent longitude and latitude values of a geo location', + + serialize(value: DbPoint) { + // Check type of value + if (value.type !== 'Point') { + throw new Error(`PointScalar can only serialize Geometry type 'Point' values`) + } + return value + }, + + parseValue(value): DbPoint { + const point = JSON.parse(value) as DbPoint + return point + }, + + parseLiteral(ast) { + if (ast.kind !== Kind.STRING) { + throw new TypeError(`${String(ast)} is not a valid Geometry value.`) + } + + const point = JSON.parse(ast.value) as DbPoint + return point + }, +}) diff --git a/backend/src/graphql/schema.ts b/backend/src/graphql/schema.ts index 18214861f..856844c94 100644 --- a/backend/src/graphql/schema.ts +++ b/backend/src/graphql/schema.ts @@ -4,21 +4,27 @@ import { Decimal } from 'decimal.js-light' import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' +import { Location } from '@model/Location' + import { isAuthorized } from './directive/isAuthorized' import { DecimalScalar } from './scalar/Decimal' +import { LocationScalar } from './scalar/Location' export const schema = async (): Promise => { return buildSchema({ resolvers: [path.join(__dirname, 'resolver', `!(*.test).{js,ts}`)], authChecker: isAuthorized, - scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], + scalarsMap: [ + { type: Decimal, scalar: DecimalScalar }, + { type: Location, scalar: LocationScalar }, + ], validate: { validationError: { target: false }, skipMissingProperties: true, skipNullProperties: true, - skipUndefinedProperties: false, - forbidUnknownValues: true, - stopAtFirstError: true, + skipUndefinedProperties: true, + forbidUnknownValues: false, + stopAtFirstError: false, }, }) } From 0dd70db539b5bb800aff93f48cded0c90bb7d7be Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 24 Jan 2024 18:15:33 +0100 Subject: [PATCH 60/85] fix not working fail2ban, add jails for nginx --- deployment/bare_metal/nginx/common/limit_requests.conf | 3 ++- deployment/hetzner_cloud/cloudConfig.yaml | 1 + deployment/hetzner_cloud/install.sh | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/nginx/common/limit_requests.conf b/deployment/bare_metal/nginx/common/limit_requests.conf index e9026ee81..c9501fd64 100644 --- a/deployment/bare_metal/nginx/common/limit_requests.conf +++ b/deployment/bare_metal/nginx/common/limit_requests.conf @@ -1,3 +1,4 @@ limit_req_zone $binary_remote_addr zone=frontend:20m rate=5r/s; limit_req_zone $binary_remote_addr zone=backend:25m rate=15r/s; -limit_req_zone $binary_remote_addr zone=api:5m rate=30r/s; \ No newline at end of file +limit_req_zone $binary_remote_addr zone=api:5m rate=30r/s; +limit_conn_zone $binary_remote_addr zone=addr:10m; \ No newline at end of file diff --git a/deployment/hetzner_cloud/cloudConfig.yaml b/deployment/hetzner_cloud/cloudConfig.yaml index 86e7d5724..84658705f 100644 --- a/deployment/hetzner_cloud/cloudConfig.yaml +++ b/deployment/hetzner_cloud/cloudConfig.yaml @@ -9,6 +9,7 @@ users: packages: - fail2ban + - python3-systemd - ufw - git - mariadb-server diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index ee539370c..e9ed69e76 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -80,6 +80,14 @@ expect eof ") echo "$SECURE_MYSQL" +# Configure fail2ban, seems to not run out of the box on Debian 12 +echo -e "[sshd]\nbackend = systemd" | tee /etc/fail2ban/jail.d/sshd.conf +# enable nginx-limit-req filter to block also user which exceed nginx request limiter +echo -e "[nginx-limit-req]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-limit-req.conf +# enable nginx bad request filter +echo -e "[nginx-bad-request]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-bad-request.conf +systemctl restart fail2ban + # Configure nginx rm /etc/nginx/sites-enabled/default envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf From 491c09f835c8cd700b97c9556adfba060128c6c5 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 24 Jan 2024 18:28:28 +0100 Subject: [PATCH 61/85] move definition of zones --- .../bare_metal/nginx/sites-available/gradido.conf.ssl.template | 3 ++- .../bare_metal/nginx/sites-available/gradido.conf.template | 3 ++- .../nginx/sites-available/update-page.conf.ssl.template | 2 +- .../bare_metal/nginx/sites-available/update-page.conf.template | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index 822c326d0..d8ed50ba4 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -1,3 +1,5 @@ +include /etc/nginx/common/limit_requests.conf; + server { if ($host = $COMMUNITY_HOST) { return 301 https://$host$request_uri; @@ -21,7 +23,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index 1f673ee41..e0f382467 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -1,3 +1,5 @@ +include /etc/nginx/common/limit_requests.conf; + server { server_name $COMMUNITY_HOST; @@ -6,7 +8,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template index ee7732230..fd41c333d 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -1,3 +1,4 @@ +include /etc/nginx/common/limit_requests.conf; server { if ($host = $COMMUNITY_HOST) { @@ -21,7 +22,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.template index 38dfb2d02..be91abc88 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.template @@ -1,3 +1,4 @@ +include /etc/nginx/common/limit_requests.conf; server { server_name $COMMUNITY_HOST; @@ -6,7 +7,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; From 7c0bc5ae357b4072ab273b763900af70a82846d7 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 25 Jan 2024 02:11:22 +0100 Subject: [PATCH 62/85] add GeometryTransformer and configure db-connection --- backend/src/typeorm/connection.ts | 1 + backend/yarn.lock | 14 ++++++++ .../0081-introduce_gms_registration/User.ts | 9 ++++- database/package.json | 5 ++- database/src/typeorm/GeometryTransformer.ts | 34 +++++++++++++++++++ database/yarn.lock | 17 ++++++++++ 6 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 database/src/typeorm/GeometryTransformer.ts diff --git a/backend/src/typeorm/connection.ts b/backend/src/typeorm/connection.ts index 3c8307478..104f6449d 100644 --- a/backend/src/typeorm/connection.ts +++ b/backend/src/typeorm/connection.ts @@ -30,6 +30,7 @@ export class Connection { Connection.instance = await createConnection({ name: 'default', type: 'mysql', + legacySpatialSupport: false, host: CONFIG.DB_HOST, port: CONFIG.DB_PORT, username: CONFIG.DB_USER, diff --git a/backend/yarn.lock b/backend/yarn.lock index 234dc817a..91186187b 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -3483,6 +3483,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +geojson@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0" + integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -3698,11 +3703,13 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: crypto "^1.0.1" decimal.js-light "^2.5.1" dotenv "^10.0.0" + geojson "^0.5.0" mysql2 "^2.3.0" reflect-metadata "^0.1.13" ts-mysql-migrate "^1.0.2" typeorm "^0.3.16" uuid "^8.3.2" + wkx "^0.5.0" grapheme-splitter@^1.0.4: version "1.0.4" @@ -7301,6 +7308,13 @@ with@^7.0.0: assert-never "^1.2.1" babel-walk "3.0.0-canary-5" +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== + dependencies: + "@types/node" "*" + word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" diff --git a/database/entity/0081-introduce_gms_registration/User.ts b/database/entity/0081-introduce_gms_registration/User.ts index f91129f31..cdbd36441 100644 --- a/database/entity/0081-introduce_gms_registration/User.ts +++ b/database/entity/0081-introduce_gms_registration/User.ts @@ -13,6 +13,7 @@ import { Contribution } from '../Contribution' import { ContributionMessage } from '../ContributionMessage' import { UserContact } from '../UserContact' import { UserRole } from '../UserRole' +import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -125,7 +126,13 @@ export class User extends BaseEntity { @Column({ name: 'gms_allowed', type: 'bool', default: true }) gmsAllowed: boolean - @Column({ name: 'location', type: 'geometry', default: null, nullable: true }) + @Column({ + name: 'location', + type: 'geometry', + default: null, + nullable: true, + transformer: GeometryTransformer, + }) location: Geometry | null @Column({ diff --git a/database/package.json b/database/package.json index 8e1a99826..d1a9a2059 100644 --- a/database/package.json +++ b/database/package.json @@ -21,6 +21,7 @@ "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "^3.2.1", "@types/faker": "^5.5.9", + "@types/geojson": "^7946.0.13", "@types/node": "^16.10.3", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", @@ -45,11 +46,13 @@ "crypto": "^1.0.1", "decimal.js-light": "^2.5.1", "dotenv": "^10.0.0", + "geojson": "^0.5.0", "mysql2": "^2.3.0", "reflect-metadata": "^0.1.13", "ts-mysql-migrate": "^1.0.2", "typeorm": "^0.3.16", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "wkx": "^0.5.0" }, "engines": { "node": ">=14" diff --git a/database/src/typeorm/GeometryTransformer.ts b/database/src/typeorm/GeometryTransformer.ts new file mode 100644 index 000000000..7e73d02a5 --- /dev/null +++ b/database/src/typeorm/GeometryTransformer.ts @@ -0,0 +1,34 @@ +/* eslint-disable camelcase */ +import { Geometry as wkx_Geometry } from 'wkx' +import { Geometry } from 'geojson' +import { ValueTransformer } from 'typeorm/decorator/options/ValueTransformer' + +/** + * TypeORM transformer to convert GeoJSON to MySQL WKT (Well Known Text) e.g. POINT(LAT, LON) and back + */ +export const GeometryTransformer: ValueTransformer = { + to: (geojson: Geometry): string | null => { + console.log('GeometryTransformer to: geojson=', geojson) + if (geojson) { + const wkxg = wkx_Geometry.parseGeoJSON(geojson) + console.log('GeometryTransformer to: wkxg=', wkxg) + const str = wkxg.toWkt() + console.log('GeometryTransformer to: str=', str) + return str + } + return null + }, + + from: (wkb: string): Record | null => { + // wkb ? wkx_Geometry.parse(wkb).toGeoJSON() : undefined + console.log('GeometryTransformer from: wbk=', wkb) + if (!wkb) { + return null + } + const record = wkx_Geometry.parse(wkb) + console.log('GeometryTransformer from: record=', record) + const str = record.toGeoJSON() + console.log('GeometryTransformer from: str=', str) + return str + }, +} diff --git a/database/yarn.lock b/database/yarn.lock index d8a0d6ffb..fd5598693 100644 --- a/database/yarn.lock +++ b/database/yarn.lock @@ -143,6 +143,11 @@ resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.5.9.tgz#588ede92186dc557bff8341d294335d50d255f0c" integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA== +"@types/geojson@^7946.0.13": + version "7946.0.13" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.13.tgz#e6e77ea9ecf36564980a861e24e62a095988775e" + integrity sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ== + "@types/json-schema@^7.0.9": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" @@ -1132,6 +1137,11 @@ generate-function@^2.3.1: dependencies: is-property "^1.0.2" +geojson@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0" + integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -2502,6 +2512,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== + dependencies: + "@types/node" "*" + word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" From ee40603637d55921bb000fbe2e81cbf9cdb4fbea Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 30 Jan 2024 21:39:12 +0100 Subject: [PATCH 63/85] use params instead of query for send/identifier route --- backend/src/config/index.ts | 2 +- backend/src/graphql/arg/UserArgs.ts | 6 +- backend/src/graphql/model/User.ts | 3 + .../graphql/resolver/TransactionResolver.ts | 2 +- backend/src/graphql/resolver/UserResolver.ts | 7 +- .../resolver/util/findUserByIdentifier.ts | 39 +++-- backend/src/util/communityUser.ts | 1 + .../0081-user_join_community/Community.ts | 70 +++++++++ .../entity/0081-user_join_community/User.ts | 138 ++++++++++++++++++ database/entity/Community.ts | 2 +- database/entity/User.ts | 2 +- .../migrations/0081-user_join_community.ts | 11 ++ dht-node/src/config/index.ts | 2 +- federation/src/config/index.ts | 2 +- frontend/src/components/CommunitySwitch.vue | 54 +++++-- .../components/GddSend/TransactionForm.vue | 58 +++----- frontend/src/graphql/queries.js | 17 +-- frontend/src/pages/Send.vue | 2 +- frontend/src/routes/routes.js | 4 +- 19 files changed, 328 insertions(+), 94 deletions(-) create mode 100644 database/entity/0081-user_join_community/Community.ts create mode 100644 database/entity/0081-user_join_community/User.ts create mode 100644 database/migrations/0081-user_join_community.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 1ec5a98e6..ee90261f4 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions', + DB_VERSION: '0081-user_join_community', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/backend/src/graphql/arg/UserArgs.ts b/backend/src/graphql/arg/UserArgs.ts index 633ed5e20..406be14cb 100644 --- a/backend/src/graphql/arg/UserArgs.ts +++ b/backend/src/graphql/arg/UserArgs.ts @@ -3,11 +3,11 @@ import { ArgsType, Field } from 'type-graphql' @ArgsType() export class UserArgs { - @Field({ nullable: false }) + @Field() @IsString() identifier: string - @Field({ nullable: true }) + @Field() @IsString() - communityIdentifier?: string + communityIdentifier: string } diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index cd188f49f..d24a717c4 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -10,6 +10,9 @@ export class User { this.id = user.id this.foreign = user.foreign this.communityUuid = user.communityUuid + if (user.community) { + this.communityName = user.community.name + } this.gradidoID = user.gradidoID this.alias = user.alias if (user.emailContact) { diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index b4fd5c4e3..00894ecd3 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -432,7 +432,7 @@ export class TransactionResolver { const senderUser = getUser(context) if (!recipientCommunityIdentifier || (await isHomeCommunity(recipientCommunityIdentifier))) { - // processing sendCoins within sender and recepient are both in home community + // processing sendCoins within sender and recipient are both in home community const recipientUser = await findUserByIdentifier( recipientIdentifier, recipientCommunityIdentifier, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 1f21abbb9..6079ac634 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -428,7 +428,7 @@ export class UserResolver { const userContact = await DbUserContact.findOneOrFail({ where: { emailVerificationCode: code }, relations: ['user'], - }).catch(() => { + }).catch((e) => { throw new LogError('Could not login with emailVerificationCode') }) logger.debug('userContact loaded...') @@ -821,11 +821,6 @@ export class UserResolver { ): Promise { const foundDbUser = await findUserByIdentifier(identifier, communityIdentifier) const modelUser = new User(foundDbUser) - if (!foundDbUser.communityUuid) { - modelUser.communityName = (await Promise.resolve(getHomeCommunity())).name - } else { - modelUser.communityName = await getCommunityName(foundDbUser.communityUuid) - } return modelUser } } diff --git a/backend/src/graphql/resolver/util/findUserByIdentifier.ts b/backend/src/graphql/resolver/util/findUserByIdentifier.ts index 6b7f1bccc..633049afb 100644 --- a/backend/src/graphql/resolver/util/findUserByIdentifier.ts +++ b/backend/src/graphql/resolver/util/findUserByIdentifier.ts @@ -1,3 +1,5 @@ +import { FindOptionsWhere } from '@dbTools/typeorm' +import { Community } from '@entity/Community' import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { validate, version } from 'uuid' @@ -6,15 +8,26 @@ import { LogError } from '@/server/LogError' import { VALID_ALIAS_REGEX } from './validateAlias' +/** + * + * @param identifier could be gradidoID, alias or email of user + * @param communityIdentifier could be uuid or name of community + * @returns + */ export const findUserByIdentifier = async ( identifier: string, - communityIdentifier?: string, + communityIdentifier: string, ): Promise => { let user: DbUser | null + const communityWhere: FindOptionsWhere = + validate(communityIdentifier) && version(communityIdentifier) === 4 + ? { communityUuid: communityIdentifier } + : { name: communityIdentifier } + if (validate(identifier) && version(identifier) === 4) { user = await DbUser.findOne({ - where: { gradidoID: identifier, communityUuid: communityIdentifier }, - relations: ['emailContact'], + where: { gradidoID: identifier, community: communityWhere }, + relations: ['emailContact', 'community'], }) if (!user) { throw new LogError('No user found to given identifier(s)', identifier, communityIdentifier) @@ -24,28 +37,24 @@ export const findUserByIdentifier = async ( where: { email: identifier, emailChecked: true, + user: { + community: communityWhere, + }, }, - relations: ['user'], + relations: ['user', 'user.community'], }) if (!userContact) { - throw new LogError('No user with this credentials', identifier) + throw new LogError('No user with this credentials', identifier, communityIdentifier) } if (!userContact.user) { - throw new LogError('No user to given contact', identifier) - } - if (userContact.user.communityUuid !== communityIdentifier) { - throw new LogError( - 'Found user to given contact, but belongs to other community', - identifier, - communityIdentifier, - ) + throw new LogError('No user to given contact', identifier, communityIdentifier) } user = userContact.user user.emailContact = userContact } else if (VALID_ALIAS_REGEX.exec(identifier)) { user = await DbUser.findOne({ - where: { alias: identifier, communityUuid: communityIdentifier }, - relations: ['emailContact'], + where: { alias: identifier, community: communityWhere }, + relations: ['emailContact', 'community'], }) if (!user) { throw new LogError('No user found to given identifier(s)', identifier, communityIdentifier) diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index bad06f201..c4c420d51 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -50,6 +50,7 @@ const communityDbUser: dbUser = { }, foreign: false, communityUuid: '55555555-4444-4333-2222-11111111', + community: null, } const communityUser = new User(communityDbUser) diff --git a/database/entity/0081-user_join_community/Community.ts b/database/entity/0081-user_join_community/Community.ts new file mode 100644 index 000000000..1c6b36be3 --- /dev/null +++ b/database/entity/0081-user_join_community/Community.ts @@ -0,0 +1,70 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { User } from '../User' + +@Entity('communities') +export class Community extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'foreign', type: 'bool', nullable: false, default: true }) + foreign: boolean + + @Column({ name: 'url', length: 255, nullable: false }) + url: string + + @Column({ name: 'public_key', type: 'binary', length: 32, nullable: false }) + publicKey: Buffer + + @Column({ name: 'private_key', type: 'binary', length: 64, nullable: true }) + privateKey: Buffer | null + + @Column({ + name: 'community_uuid', + type: 'char', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + communityUuid: string | null + + @Column({ name: 'authenticated_at', type: 'datetime', nullable: true }) + authenticatedAt: Date | null + + @Column({ name: 'name', type: 'varchar', length: 40, nullable: true }) + name: string | null + + @Column({ name: 'description', type: 'varchar', length: 255, nullable: true }) + description: string | null + + @CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true }) + creationDate: Date | null + + @CreateDateColumn({ + name: 'created_at', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP(3)', + nullable: false, + }) + createdAt: Date + + @UpdateDateColumn({ + name: 'updated_at', + type: 'datetime', + onUpdate: 'CURRENT_TIMESTAMP(3)', + nullable: true, + }) + updatedAt: Date | null + + @OneToMany(() => User, (user) => user.community) + @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) + users: User[] +} diff --git a/database/entity/0081-user_join_community/User.ts b/database/entity/0081-user_join_community/User.ts new file mode 100644 index 000000000..28141029d --- /dev/null +++ b/database/entity/0081-user_join_community/User.ts @@ -0,0 +1,138 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, + OneToOne, + ManyToOne, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { UserContact } from '../UserContact' +import { UserRole } from '../UserRole' +import { Community } from '../Community' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ type: 'bool', default: false }) + foreign: boolean + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'community_uuid', + type: 'char', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + communityUuid: string + + @ManyToOne(() => Community, (community) => community.users) + @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) + community: Community | null + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) + @JoinColumn({ name: 'email_id' }) + emailContact: UserContact + + @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) + emailId: number | null + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ + name: 'password_encryption_type', + type: 'int', + unsigned: true, + nullable: false, + default: 0, + }) + passwordEncryptionType: number + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ type: 'bool', default: false }) + hideAmountGDD: boolean + + @Column({ type: 'bool', default: false }) + hideAmountGDT: boolean + + @OneToMany(() => UserRole, (userRole) => userRole.user) + @JoinColumn({ name: 'user_id' }) + userRoles: UserRole[] + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] + + @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) + @JoinColumn({ name: 'user_id' }) + userContacts?: UserContact[] +} diff --git a/database/entity/Community.ts b/database/entity/Community.ts index d398cf584..d286749eb 100644 --- a/database/entity/Community.ts +++ b/database/entity/Community.ts @@ -1 +1 @@ -export { Community } from './0068-community_tables_public_key_length/Community' +export { Community } from './0081-user_join_community/Community' diff --git a/database/entity/User.ts b/database/entity/User.ts index 21785ee9c..b75693674 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0073-introduce_foreign_user_in_users_table/User' +export { User } from './0081-user_join_community/User' diff --git a/database/migrations/0081-user_join_community.ts b/database/migrations/0081-user_join_community.ts new file mode 100644 index 000000000..6e40cb414 --- /dev/null +++ b/database/migrations/0081-user_join_community.ts @@ -0,0 +1,11 @@ +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'ALTER TABLE users MODIFY community_uuid VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;', + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'ALTER TABLE users MODIFY community_uuid VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', + ) +} diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index fd3df5c21..632ccdba3 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -4,7 +4,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions', + DB_VERSION: '0081-user_join_community', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 821df574a..8a8947b93 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions', + DB_VERSION: '0081-user_join_community', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/frontend/src/components/CommunitySwitch.vue b/frontend/src/components/CommunitySwitch.vue index f9ecc804d..2c47dd08e 100644 --- a/frontend/src/components/CommunitySwitch.vue +++ b/frontend/src/components/CommunitySwitch.vue @@ -1,16 +1,23 @@