diff --git a/README.md b/README.md index 8be2894..9d0bc5d 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,19 @@ ztncui is a web user interface for a standalone ZeroTier network controller. It ## Configuration -How to configure this app: by an admin panel, a plain file with SSH, or any other way. +No particular configuration is needed after initial installation. ## Documentation - * Official documentation: Link to the official documentation of this app + * [Official documentation](https://key-networks.com/ztncui/) * YunoHost documentation: If specific documentation is needed, feel free to contribute. ## YunoHost specific features #### Multi-users support - * No LDAP and HTTP auth supported. ztncui implements its own `passwd` file. - * Can the app be used by multiple users? Yes. See `/opt/key-networks/ztncui/src/etc/passwd` + * No LDAP and HTTP auth supported. + * Can the app be used by multiple users? Yes, you have to add them manually in `/opt/key-networks/ztncui/src/etc/passwd`, see ztncui documentation. #### Supported architectures @@ -40,7 +40,7 @@ How to configure this app: by an admin panel, a plain file with SSH, or any othe ## Limitations -* [ZeroTier for YunoHost](https://github.com/tituspijean/zerotier_ynh) has to be installed beforehand. +* [ZeroTier for YunoHost](https://github.com/YunoHost-Apps/zerotier_ynh) has to be installed beforehand. ## Additional information diff --git a/check_process b/check_process index dd1c025..89023cf 100644 --- a/check_process +++ b/check_process @@ -5,28 +5,31 @@ ;; Test complet ; Manifest - domain="domain.tld" (DOMAIN) - path="/" (PATH) - admin="john" (USER) - language="fr" - is_public=1 (PUBLIC|public=1|private=0) - password="pass" - port="666" (PORT) + domain="domain.tld" (DOMAIN) + path="/" (PATH) + admin="john" (USER) + language="fr" + is_public=1 (PUBLIC|public=1|private=0) + password="pass" + port="666" (PORT) + ; pre-install + sudo yunohost app fetchlist + sudo yunohost app install zerotier ; Checks - pkg_linter=1 - setup_sub_dir=0 - setup_root=1 - setup_nourl=0 - setup_private=1 - setup_public=1 - upgrade=1 - upgrade=1 from_commit=CommitHash - backup_restore=1 - multi_instance=1 - # This test is no longer necessary since the version 2.7 (PR: https://github.com/YunoHost/yunohost/pull/304), you can still do it if your app could be installed with this version. - # incorrect_path=1 - port_already_use=0 - change_url=1 + pkg_linter=1 + setup_sub_dir=0 + setup_root=1 + setup_nourl=0 + setup_private=1 + setup_public=1 + upgrade=1 + ;upgrade=1 from_commit=CommitHash + backup_restore=1 + multi_instance=0 + # This test is no longer necessary since the version 2.7 (PR: https://github.com/YunoHost/yunohost/pull/304), you can still do it if your app could be installed with this version. + # incorrect_path=1 + port_already_use=0 + change_url=1 ;;; Levels # If the level 5 (Package linter) is forced to 1. Please add justifications here. Level 5=auto @@ -37,4 +40,3 @@ Notification=none ; commit=CommitHash name=Name and date of the commit. manifest_arg=domain=DOMAIN&path=PATH&admin=USER&language=fr&is_public=1&password=pass&port=666& - diff --git a/conf/start.sh b/conf/start.sh deleted file mode 100644 index 43f8d7f..0000000 --- a/conf/start.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -pushd __FINALPATH__/src/ - npm start -popd diff --git a/conf/systemd.service b/conf/systemd.service index d2f3180..b5a4e27 100644 --- a/conf/systemd.service +++ b/conf/systemd.service @@ -4,11 +4,11 @@ After=network.target [Service] Type=simple -User=root -Group=root -Environment="PATH=__ENV_PATH__" -WorkingDirectory=__FINALPATH__/src/ -ExecStart=/bin/bash __FINALPATH__/src/start.sh >> /var/log/__APP__/__APP__.log 2>&1 +User=ztncui +Group=ztncui +Environment="PATH=__PATH__" +WorkingDirectory=__FINAL_PATH__/src/ +ExecStart=__NODEJS_PATH__/npm start [Install] WantedBy=multi-user.target diff --git a/manifest.json b/manifest.json index b67c334..1c013be 100644 --- a/manifest.json +++ b/manifest.json @@ -1,45 +1,73 @@ { - "name": "Zerotier UI", - "id": "ztncui", - "packaging_format": 1, - "description": { - "en": "A user interface for the ZeroTier network controller", - "fr": "Une interface utilisateur pour le contrôleur réseau ZeroTier" - }, - "version": "0.5.8~ynh1", - "url": "https://key-networks.com/ztncui", - "license": "gpl", - "maintainer": { - "name": "tituspijean", - "email": "tituspijean@outlook.com" - }, - "requirements": { - "yunohost": ">= 3.5" - }, - "multi_instance": false, - "services": [ - "zerotier-one" - ], - "arguments": { - "install" : [ - { - "name": "domain", - "type": "domain", - "ask": { - "en": "Choose a domain name for ztncui", - "fr": "Choisissez un nom de domaine pour ztncui" - }, - "example": "example.com" - }, - { - "name": "is_public", - "type": "boolean", - "ask": { - "en": "Is it a public application?", - "fr": "Est-ce une application publique ?" - }, - "default": false - } - ] - } + "name": "Zerotier UI", + "id": "ztncui", + "packaging_format": 1, + "description": { + "en": "ZeroTier network controller user interface", + "fr": "Interface utilisateur pour le contrôleur de réseau ZeroTier" + }, + "version": "0.5.8~ynh1", + "url": "https://key-networks.com/ztncui", + "license": "GPL-3.0-only", + "maintainer": { + "name": "tituspijean", + "email": "tituspijean@outlook.com" + }, + "requirements": { + "yunohost": ">= 3.7" + }, + "services": [], + "multi_instance": false, + "arguments": { + "install": [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain name for ztncui", + "fr": "Choisissez un nom de domaine pour ztncui" + }, + "help": { + "en": "REMINDER: ztncui needs the ZeroTier app to be already installed.", + "fr": "RAPPEL: ztncui nécessite que l'app ZeroTier soit déjà installée." + }, + "example": "zt.example.com" + }, + { + "name": "is_public", + "type": "boolean", + "ask": { + "en": "Is it a public application?", + "fr": "Est-ce une application publique ?" + }, + "help": { + "en": "Ztncui has its own login system, but setting it as private is advised.", + "fr": "Ztncui a son propre système de connexion, mais la rendre privée est conseillé." + }, + "default": false + }, + { + "name": "admin", + "type": "user", + "ask": { + "en": "Choose an admin user", + "fr": "Choisissez l’administrateur" + }, + "example": "johndoe" + }, + { + "name": "password", + "type": "password", + "ask": { + "en": "Set the administrator password", + "fr": "Définissez le mot de passe administrateur" + }, + "help": { + "en": "It will always be asked by Ztncui, in addition to your YunoHost credentials if set to private.", + "fr": "Il sera toujours demandé par Ztncui, en plus des identifiants YunoHost si l'app est privée." + }, + "example": "Choose a password" + } + ] + } } diff --git a/scripts/_common.sh b/scripts/_common.sh index d5160da..f55d066 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -4,7 +4,10 @@ # COMMON VARIABLES #================================================= -nodejs_version=10 +nodejs_version=12 + +# dependencies used by the app +pkg_dependencies="g++" #================================================= # PERSONAL HELPERS @@ -14,6 +17,21 @@ nodejs_version=10 # EXPERIMENTAL HELPERS #================================================= +#!/bin/bash + +# Execute a command as another user +# usage: exec_as USER COMMAND [ARG ...] +exec_as() { + local USER=$1 + shift 1 + + if [[ $USER = $(whoami) ]]; then + eval "$@" + else + sudo PATH=$PATH -u "$USER" "$@" + fi +} + #================================================= # FUTURE OFFICIAL HELPERS #================================================= diff --git a/scripts/install b/scripts/install index eabc49f..21f9cbe 100644 --- a/scripts/install +++ b/scripts/install @@ -27,6 +27,8 @@ ynh_abort_if_errors domain=$YNH_APP_ARG_DOMAIN path_url="/" #$YNH_APP_ARG_PATH is_public=$YNH_APP_ARG_IS_PUBLIC +admin=$YNH_APP_ARG_ADMIN +password=$YNH_APP_ARG_PASSWORD ### If it's a multi-instance app, meaning it can be installed several times independently ### The id of the app as stated in the manifest is available as $YNH_APP_ID @@ -53,9 +55,12 @@ app=$YNH_APP_INSTANCE_NAME ### The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. ynh_script_progression --message="Validating installation parameters..." --time --weight=1 +# Testing if ZeroTier is installed +yunohost app list | grep -q "id: zerotier" || ynh_die "ZeroTier is needed, but it is not installed. There is a package for that!" + ### If the app uses nginx as web server (written in HTML/PHP in most cases), the final path should be "/var/www/$app". ### If the app provides an internal web server (or uses another application server such as uwsgi), the final path should be "/opt/yunohost/$app" -final_path=/opt/key-networks/ztncui +final_path=/opt/yunohost/$app test ! -e "$final_path" || ynh_die --message="This path already contains a folder" # Register (book) web path @@ -105,6 +110,8 @@ ynh_script_progression --message="Installing dependencies..." --time --weight=1 ### - As well as the section "REINSTALL DEPENDENCIES" in the restore script ### - And the section "UPGRADE DEPENDENCIES" in the upgrade script +ynh_install_app_dependencies $pkg_dependencies + ynh_install_nodejs --nodejs_version=$nodejs_version ynh_use_nodejs @@ -137,7 +144,7 @@ ynh_add_nginx_config ynh_script_progression --message="Configuring system user..." --time --weight=1 # Create a system user -ynh_system_user_create --username=$app +ynh_system_user_create $app $final_path #================================================= # SPECIFIC SETUP @@ -146,8 +153,13 @@ ynh_system_user_create --username=$app #================================================= ynh_script_progression --message="Performing Node app installation..." --time --weight=1 +chown -R $app: $final_path + pushd $final_path/src - npm install + exec_as $app $nodejs_path/npm --loglevel=error install node-gyp + exec_as $app $nodejs_path/npm --loglevel=error install + exec_as $app $nodejs_path/npm --loglevel=error install argon2-cli + exec_as $app $nodejs_path/npm --loglevel=error audit fix popd #================================================= @@ -158,15 +170,19 @@ popd mkdir -p $final_path env_file=$final_path/src/.env touch $env_file +chmod 600 $env_file echo "ZT_TOKEN=$(> $env_file +echo "ZT_ADDR=localhost:$(> $env_file echo "HTTP_PORT=$port" >> $env_file -cp ../conf/start.sh $final_path/src/ -ynh_replace_string "__APP__" "$app" "$final_path/src/start.sh" -ynh_replace_string "__FINALPATH__" "$final_path" "$final_path/src/start.sh" +# Setup user credentials file +hashedpassword=$(echo -n "$password" | $final_path/src/node_modules/.bin/argon2-cli -e) +echo "{\"$admin\":{\"name\":\"$admin\",\"pass_set\":true,\"hash\":\"$hashedpassword\"}}" >> "$final_path/src/etc/passwd" -cp $final_path/src/etc/default.passwd $final_path/src/etc/passwd +# Store user settings +ynh_app_setting_set --app=$app --key=admin --value=$admin +ynh_app_setting_set --app=$app --key=hashedpassword --value=$hashedpassword #================================================= # LINK CERTIFICATES @@ -175,8 +191,8 @@ cp $final_path/src/etc/default.passwd $final_path/src/etc/passwd # Even though one can stay in HTTP mode, the ztncui requires SSL certificates # let's use the ones of the domain pushd $final_path/src/etc/tls - ln -s /etc/yunohost/certs/$domain/key.pem privkey.pem - ln -s /etc/yunohost/certs/$domain/crt.pem fullchain.pem + cp /etc/yunohost/certs/$domain/key.pem privkey.pem + cp /etc/yunohost/certs/$domain/crt.pem fullchain.pem popd #================================================= @@ -195,10 +211,13 @@ ynh_script_progression --message="Configuring a systemd service..." --time --wei ### - As well as the section "RESTORE SYSTEMD" in the restore script ### - And the section "SETUP SYSTEMD" in the upgrade script +# Set the systemd service settings +ynh_replace_string "__PATH__" "$PATH" "../conf/systemd.service" +ynh_replace_string "__NODEJS_PATH__" "$nodejs_path" "../conf/systemd.service" +ynh_replace_string "__FINAL_PATH__" "$final_path" "../conf/systemd.service" + # Create a dedicated systemd config ynh_add_systemd_config -ynh_replace_string "__ENV_PATH__" "$PATH" "/etc/systemd/system/$app.service" -systemctl daemon-reload #================================================= # GENERIC FINALIZATION @@ -270,13 +289,12 @@ ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$ap #================================================= # SETUP SSOWAT #================================================= -ynh_script_progression --message="Configuring SSOwat..." --time --weight=1 +ynh_script_progression --message="Configuring SSOwat..." # Make app public if necessary if [ $is_public -eq 1 ] then - # unprotected_uris allows SSO credentials to be passed anyway. - ynh_app_setting_set --app=$app --key=unprotected_uris --value="/" + ynh_permission_update --permission "main" --add visitors fi #================================================= diff --git a/scripts/remove b/scripts/remove index b201fd3..9cf7ddf 100644 --- a/scripts/remove +++ b/scripts/remove @@ -33,11 +33,21 @@ then yunohost service remove $app fi +#================================================= +# STOP AND REMOVE SERVICE +#================================================= +ynh_script_progression --message="Stopping and removing the systemd service..." --time --weight=1 + +# Remove the dedicated systemd config +ynh_remove_systemd_config + #================================================= # REMOVE DEPENDENCIES #================================================= ynh_script_progression --message="Removing dependencies..." --time --weight=1 +# Remove metapackage and its dependencies +ynh_remove_app_dependencies ynh_remove_nodejs #================================================= diff --git a/scripts/upgrade b/scripts/upgrade index 1957c55..f4c271a 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -20,6 +20,9 @@ domain=$(ynh_app_setting_get --app=$app --key=domain) path_url=$(ynh_app_setting_get --app=$app --key=path) is_public=$(ynh_app_setting_get --app=$app --key=is_public) final_path=$(ynh_app_setting_get --app=$app --key=final_path) +port=$(ynh_app_setting_get --app=$app --key=port) +admin=$(ynh_app_setting_get --app=$app --key=admin) +hashedpassword=$(ynh_app_setting_get --app=$app --key=hashedpassword) #================================================= # CHECK VERSION @@ -38,15 +41,6 @@ upgrade_type=$(ynh_check_app_version_changed) #================================================= ynh_script_progression --message="Ensuring downward compatibility..." --time --weight=1 -# Fix is_public as a boolean value -if [ "$is_public" = "Yes" ]; then - ynh_app_setting_set --app=$app --key=is_public --value=1 - is_public=1 -elif [ "$is_public" = "No" ]; then - ynh_app_setting_set --app=$app --key=is_public --value=0 - is_public=0 -fi - # If db_name doesn't exist, create it if [ -z "$db_name" ]; then db_name=$(ynh_sanitize_dbid --db_name=$app) @@ -119,7 +113,10 @@ ynh_add_nginx_config #================================================= ynh_script_progression --message="Upgrading dependencies..." --time --weight=1 -#ynh_install_app_dependencies $pkg_dependencies +ynh_install_app_dependencies $pkg_dependencies + +ynh_install_nodejs --nodejs_version=$nodejs_version +ynh_use_nodejs #================================================= # CREATE DEDICATED USER @@ -127,7 +124,7 @@ ynh_script_progression --message="Upgrading dependencies..." --time --weight=1 ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 # Create a dedicated user (if not existing) -ynh_system_user_create --username=$app +ynh_system_user_create $app $final_path #================================================= # SPECIFIC UPGRADE @@ -136,8 +133,41 @@ ynh_system_user_create --username=$app #================================================= ynh_script_progression --message="Performing Node app installation..." --time --weight=1 +chown -R $app: $final_path + pushd $final_path/src - npm install + exec_as $app $nodejs_path/npm --loglevel=error install node-gyp + exec_as $app $nodejs_path/npm --loglevel=error install + exec_as $app $nodejs_path/npm --loglevel=error install argon2-cli + exec_as $app $nodejs_path/npm --loglevel=error audit fix +popd + +#================================================= +# MODIFY A CONFIG FILE +#================================================= + +# Setup env file +mkdir -p $final_path +env_file=$final_path/src/.env +touch $env_file +chmod 600 $env_file + +echo "ZT_TOKEN=$(> $env_file +echo "ZT_ADDR=localhost:$(> $env_file +echo "HTTP_PORT=$port" >> $env_file + +# Setup user credentials file +echo "{\"$admin\":{\"name\":\"$admin\",\"pass_set\":true,\"hash\":\"$hashedpassword\"}}" >> "$final_path/src/etc/passwd" + +#================================================= +# LINK CERTIFICATES +#================================================= + +# Even though one can stay in HTTP mode, the ztncui requires SSL certificates +# let's use the ones of the domain +pushd $final_path/src/etc/tls + cp /etc/yunohost/certs/$domain/key.pem privkey.pem + cp /etc/yunohost/certs/$domain/crt.pem fullchain.pem popd #================================================= @@ -153,6 +183,11 @@ ynh_use_logrotate --non-append #================================================= ynh_script_progression --message="Upgrading systemd configuration..." --time --weight=1 +# Set the systemd service settings +ynh_replace_string "__PATH__" "$PATH" "../conf/systemd.service" +ynh_replace_string "__NODEJS_PATH__" "$nodejs_path" "../conf/systemd.service" +ynh_replace_string "__FINAL_PATH__" "$final_path" "../conf/systemd.service" + # Create a dedicated systemd config ynh_add_systemd_config @@ -163,7 +198,7 @@ ynh_add_systemd_config #================================================= # Set permissions on app files -chown -R root: $final_path +chown -R $app: $final_path #================================================= # SETUP SSOWAT