diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1cfaba4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Created from https://github.com/YunoHost/example_ynh/blob/master/.gitignore +*~ +*.sw[op] \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b499c28 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: python +before_script: + - git clone --depth 1 git://github.com/YunoHost/package_linter ../package_linter && cd ../package_linter + - mv ../vpnclient_ynh vpnclient_ynh +script: + - python -m json.tool vpnclient_ynh/manifest.json + - ./package_linter.py vpnclient_ynh +notifications: + email: false + irc: + on_success: always + on_failure: always + channels: + - "irc.geeknode.org#labriqueinter.net-dev" diff --git a/README.md b/README.md index 9a668d7..45c79cd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# VPN Client +# VPN Client [![Build Status](https://travis-ci.org/labriqueinternet/vpnclient_ynh.svg?branch=master)](https://travis-ci.org/labriqueinternet/vpnclient_ynh) [![Integration level](https://dash.yunohost.org/integration/vpnclient.svg)](https://ci-apps.yunohost.org/jenkins/job/vpnclient%20%28Community%29/lastBuild/consoleFull) +[![Install LaBriqueInterNet VPNclient with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=vpnclient) + ## Overview VPN Client app for [YunoHost](http://yunohost.org/). diff --git a/check_process b/check_process new file mode 100644 index 0000000..1a88c4c --- /dev/null +++ b/check_process @@ -0,0 +1,40 @@ +;; Test complet + ; pre-install + echo -n "Si j'avais des commandes à exécuter ce serait ici " + ; Manifest + domain="domain.tld" (DOMAIN) + path="/vpnconfig" (PATH) + ; Checks + pkg_linter=1 + setup_sub_dir=1 + setup_root=0 + setup_nourl=0 + setup_private=1 + setup_public=0 + upgrade=1 + upgrade=1 from_commit=355b24ea0cd3467d7ba1390ab7d34dd4b2500229 + upgrade=1 from_commit=1fc458110660ce775f7613091cde3c5fdcfbe4e6 + backup_restore=1 + multi_instance=0 + incorrect_path=1 + port_already_use=0 + change_url=0 +;;; Levels + Level 1=auto + Level 2=auto + Level 3=auto + Level 4=0 + Level 5=auto + Level 6=auto + Level 7=auto + Level 8=0 + Level 9=0 + Level 10=0 +;;; Options +Email=pitchum@gramaton.org +Notification=down +#;;; Upgrade options +# ; commit=65c382d138596fcb32b4c97c39398815a1dcd4e8 +# name=Name of this previous version +# manifest_arg=domain=DOMAIN&path=PATH&admin=USER&password=pass&is_public=1& +# diff --git a/conf/ynh-vpnclient b/conf/ynh-vpnclient index 910e282..aad043c 100644 --- a/conf/ynh-vpnclient +++ b/conf/ynh-vpnclient @@ -129,6 +129,10 @@ start_openvpn() { [ "${ynh_server_proto}" == tcp ] && proto=tcp-client fi + # Unset firewall to let DNS and NTP resolution works + # Firewall is reset after vpn is mounted (more details on #1016) + unset_firewall + sync_time cp /etc/openvpn/client.conf{.tpl,} @@ -199,7 +203,21 @@ stop_openvpn() { sync_time() { systemctl stop ntp - ntpd -qg &> /dev/null + timeout 20 ntpd -qg &> /dev/null + + # Some networks drop ntp port (udp 123). + # Try to get the date with an http request on the internetcube web site + if [ $? -ne 0 ]; then + http_date=`curl -sD - labriqueinter.net | grep '^Date:' | cut -d' ' -f3-6` + http_date_seconds=`date -d "${http_date}" +%s` + curr_date_seconds=`date +%s` + + # Set the new date if it's greater than the current date + # So it does if 1970 year or if old fake-hwclock date is used + if [ $http_date_seconds -ge $curr_date_seconds ]; then + date -s "${http_date}" + fi + fi systemctl start ntp } diff --git a/manifest.json b/manifest.json index 902fa42..f68ff0b 100644 --- a/manifest.json +++ b/manifest.json @@ -1,32 +1,46 @@ { "name": "VPN Client", "id": "vpnclient", + "packaging_format": 1, "description": { "en": "VPN Client", "fr": "Client VPN" }, - "license": "AGPL-3", - "developer": { + "url": "https://github.com/labriqueinternet/vpnclient_ynh", + "version": "1.1.0", + "license": "AGPL-3.0", + "maintainer": { "name": "Julien Vaubourg", "email": "julien@vaubourg.com", "url": "http://julien.vaubourg.com" }, - "multi_instance": "false", + "requirements": { + "yunohost": ">= 2.2.0", + "moulinette": ">= 2.4.0" + }, + "multi_instance": false, + "services": [ + "nginx", + "php5-fpm", + "ynh-vpnclient" + ], "arguments": { - "install" : [ + "install": [ { "name": "domain", + "type": "domain", "ask": { - "en": "Choose a domain for the web administration", - "fr": "Choisissez un domaine pour l'administration web" + "en": "Choose a domain for the web administration", + "fr": "Choisissez un domaine pour l'administration web" }, "example": "domain.org" }, { "name": "path", + "type": "path", "ask": { - "en": "Choose a path for the web administration", - "fr": "Choisissez un chemin pour l'administration web" + "en": "Choose a path for the web administration", + "fr": "Choisissez un chemin pour l'administration web" }, "example": "/vpnadmin", "default": "/vpnadmin" diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..5931e78 --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# +# Common variables +# + +pkg_dependencies="php5-fpm sipcalc dnsutils openvpn curl fake-hwclock" + + +# Helper to start/stop/.. a systemd service from a yunohost context, +# *and* the systemd service itself needs to be able to run yunohost +# commands. +# +# Hence the need to release the lock during the operation +# +# usage : ynh_systemctl yolo restart +# +function ynh_systemctl() +{ + local ACTION="$1" + local SERVICE="$2" + local LOCKFILE="/var/run/moulinette_yunohost.lock" + + # Launch the action + sudo systemctl "$ACTION" "$SERVICE" & + local SYSCTLACTION=$! + + # Save and release the lock... + cp $LOCKFILE $LOCKFILE.bkp.$$ + rm $LOCKFILE + + # Wait for the end of the action + wait $SYSCTLACTION + + # Make sure the lock is released... + while [ -f $LOCKFILE ] + do + sleep 0.1 + done + + # Restore the old lock + mv $LOCKFILE.bkp.$$ $LOCKFILE +} + +# Read the value of a key in a ynh manifest file +# +# usage: ynh_read_manifest manifest key +# | arg: manifest - Path of the manifest to read +# | arg: key - Name of the key to find +ynh_read_manifest () { + manifest="$1" + key="$2" + python3 -c "import sys, json;print(json.load(open('$manifest', encoding='utf-8'))['$key'])" +} + +# Read the upstream version from the manifest +# The version number in the manifest is defined by ~ynh +# For example : 4.3-2~ynh3 +# This include the number before ~ynh +# In the last example it return 4.3-2 +# +# usage: ynh_app_upstream_version +ynh_app_upstream_version () { + manifest_path="../manifest.json" + if [ ! -e "$manifest_path" ]; then + manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place + fi + version_key=$(ynh_read_manifest "$manifest_path" "version") + echo "${version_key/~ynh*/}" +} + +# Read package version from the manifest +# The version number in the manifest is defined by ~ynh +# For example : 4.3-2~ynh3 +# This include the number after ~ynh +# In the last example it return 3 +# +# usage: ynh_app_package_version +ynh_app_package_version () { + manifest_path="../manifest.json" + if [ ! -e "$manifest_path" ]; then + manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place + fi + version_key=$(ynh_read_manifest "$manifest_path" "version") + echo "${version_key/*~ynh/}" +} + +# Exit without error if the package is up to date +# +# This helper should be used to avoid an upgrade of a package +# when it's not needed. +# +# To force an upgrade, even if the package is up to date, +# you have to set the variable YNH_FORCE_UPGRADE before. +# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp +# +# usage: ynh_abort_if_up_to_date +ynh_abort_if_up_to_date () { + local force_upgrade=${YNH_FORCE_UPGRADE:-0} + local package_check=${PACKAGE_CHECK_EXEC:-0} + + local version=$(ynh_read_manifest "/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" "version" || echo 1.0) + local last_version=$(ynh_read_manifest "../manifest.json" "version" || echo 1.0) + if [ "$version" = "$last_version" ] + then + if [ "$force_upgrade" != "0" ] + then + echo "Upgrade forced by YNH_FORCE_UPGRADE." >&2 + unset YNH_FORCE_UPGRADE + elif [ "$package_check" != "0" ] + then + echo "Upgrade forced for package check." >&2 + else + ynh_die "Up-to-date, nothing to do" 0 + fi + fi +} diff --git a/scripts/backup b/scripts/backup index 43b6047..5b857c3 100644 --- a/scripts/backup +++ b/scripts/backup @@ -1,9 +1,16 @@ #!/bin/bash +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_abort_if_errors # Stop script if an error is detected + +#================================================= + backup_dir="${1}/apps/vpnclient" mkdir -p "${backup_dir}/" sudo cp -a /etc/openvpn/keys/ "${backup_dir}/" sudo cp -a /etc/openvpn/client.conf.tpl "${backup_dir}/" -exit 0 diff --git a/scripts/helpers b/scripts/helpers deleted file mode 100644 index f91730f..0000000 --- a/scripts/helpers +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -source /usr/share/yunohost/helpers - -# -# Helper to start/stop/.. a systemd service from a yunohost context, -# *and* the systemd service itself needs to be able to run yunohost -# commands. -# -# Hence the need to release the lock during the operation -# -# usage : ynh_systemctl yolo restart -# -function ynh_systemctl() -{ - local ACTION="$1" - local SERVICE="$2" - local LOCKFILE="/var/run/moulinette_yunohost.lock" - - # Launch the action - sudo systemctl "$ACTION" "$SERVICE" & - local SYSCTLACTION=$! - - # Save and release the lock... - cp $LOCKFILE $LOCKFILE.bkp.$$ - rm $LOCKFILE - - # Wait for the end of the action - wait $SYSCTLACTION - - # Make sure the lock is released... - while [ -f $LOCKFILE ] - do - sleep 0.1 - done - - # Restore the old lock - mv $LOCKFILE.bkp.$$ $LOCKFILE -} diff --git a/scripts/install b/scripts/install index b7747be..ed504f8 100644 --- a/scripts/install +++ b/scripts/install @@ -1,61 +1,99 @@ #!/bin/bash -# VPN Client app for YunoHost +# VPN Client app for YunoHost # Copyright (C) 2015 Julien Vaubourg # Contribute at https://github.com/labriqueinternet/vpnclient_ynh -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -# This is an upgrade? -upgrade=$([ "${VPNCLIENT_UPGRADE}" == 1 ] && echo true || echo false) +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= # Retrieve arguments -domain=${1} -url_path=${2} +domain=$YNH_APP_ARG_DOMAIN +path_url=$YNH_APP_ARG_PATH -if ! $upgrade; then - source ./helpers - source ./prerequisites -fi +app=$YNH_APP_INSTANCE_NAME -# Check domain/path availability -ynh_webpath_register vpnclient $domain $url_path || exit 1 +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= -# Install packages -packages='php5-fpm sipcalc dnsutils openvpn curl' -export DEBIAN_FRONTEND=noninteractive +# Check destination directory +final_path="/var/www/$app" +test ! -e "$final_path" || ynh_die "This path already contains a folder" -sudo apt-get --assume-yes --force-yes install ${packages} +# Normalize the url path syntax +path_url=$(ynh_normalize_url_path "$path_url") -if [ $? -ne 0 ]; then - sudo apt-get update - sudo apt-get --assume-yes --force-yes install ${packages} -fi +# Check web path availability +ynh_webpath_available "$domain" "$path_url" +# Register (book) web path +ynh_webpath_register "$app" "$domain" "$path_url" + +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= + +ynh_app_setting_set "$app" domain "$domain" +ynh_app_setting_set "$app" final_path "$final_path" + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# INSTALL DEPENDENCIES +#================================================= + +ynh_install_app_dependencies "$pkg_dependencies" + +#================================================= +# SPECIFIC SETUP +#================================================= + +# This is an upgrade? +upgrade=$([ -z ${VPNCLIENT_UPGRADE+x} ] && echo true || echo false) if ! $upgrade; then # Save arguments - sudo yunohost app setting vpnclient service_enabled -v 0 - sudo yunohost app setting vpnclient server_name -v none - sudo yunohost app setting vpnclient server_port -v 1194 - sudo yunohost app setting vpnclient server_proto -v udp - sudo yunohost app setting vpnclient ip6_addr -v none - sudo yunohost app setting vpnclient ip6_net -v none - sudo yunohost app setting vpnclient login_user -v "${login_user}" - sudo yunohost app setting vpnclient login_passphrase -v "${login_passphrase}" - sudo yunohost app setting vpnclient dns0 -v 89.234.141.66 - sudo yunohost app setting vpnclient dns1 -v 2001:913::8 + ynh_app_setting_set $app service_enabled 0 + ynh_app_setting_set $app server_name none + ynh_app_setting_set $app server_port 1194 + ynh_app_setting_set $app server_proto udp + ynh_app_setting_set $app ip6_addr none + ynh_app_setting_set $app ip6_net none + ynh_app_setting_set $app login_user "${login_user}" + ynh_app_setting_set $app login_passphrase "${login_passphrase}" + ynh_app_setting_set $app dns0 89.234.141.66 + ynh_app_setting_set $app dns1 2001:913::8 fi @@ -91,20 +129,25 @@ sudo find /var/www/vpnadmin/ -type d -exec chmod +x {} \; sudo mkdir -pm 0770 /etc/openvpn/keys/ sudo chown root:admins /etc/openvpn/keys/ -# Fix confs -## nginx -sudo sed "s||${url_path}|g" -i "/etc/nginx/conf.d/${domain}.d/vpnadmin.conf" +#================================================= +# NGINX CONFIGURATION +#================================================= + +sudo sed "s||${path_url}|g" -i "/etc/nginx/conf.d/${domain}.d/vpnadmin.conf" sudo sed 's||/var/www/vpnadmin/|g' -i "/etc/nginx/conf.d/${domain}.d/vpnadmin.conf" sudo sed 's||vpnadmin|g' -i "/etc/nginx/conf.d/${domain}.d/vpnadmin.conf" -## php-fpm +#================================================= +# PHP-FPM CONFIGURATION +#================================================= + sudo sed 's||vpnadmin|g' -i /etc/php5/fpm/pool.d/vpnadmin.conf sudo sed 's||admin|g' -i /etc/php5/fpm/pool.d/vpnadmin.conf sudo sed 's||admins|g' -i /etc/php5/fpm/pool.d/vpnadmin.conf sudo sed 's||/var/www/vpnadmin/|g' -i /etc/php5/fpm/pool.d/vpnadmin.conf # Fix sources -sudo sed "s||${url_path}|g" -i /var/www/vpnadmin/config.php +sudo sed "s||${path_url}|g" -i /var/www/vpnadmin/config.php # Copy init script sudo install -o root -g root -m 0755 ../conf/ynh-vpnclient /usr/local/bin/ @@ -138,11 +181,11 @@ if ! $upgrade; then ynh_systemctl start ynh-vpnclient # Check configuration consistency - + if [ -z "${crt_server_ca_path}" ]; then echo "WARNING: VPN Client is not started because you need to define a server CA through the web admin" >&2 fi - + if [ -z "${crt_client_key_path}" -a -z "${login_user}" ]; then echo "WARNING: VPN Client is not started because you need either a client certificate, either a username (or both)" >&2 fi @@ -150,4 +193,3 @@ fi sudo yunohost app ssowatconf -exit 0 diff --git a/scripts/prerequisites b/scripts/prerequisites deleted file mode 100644 index 4b18fc3..0000000 --- a/scripts/prerequisites +++ /dev/null @@ -1,8 +0,0 @@ -# Source me - -# Check YunoHost version (firewall hook in Moulinette) -ynh_version=$(sudo dpkg -l yunohost | grep ii | awk '{ print $3 }' | sed 's/\.//g') - -if [ "${ynh_version}" -lt 240 ]; then - echo "WARN: You need a YunoHost's version equals or greater than 2.4.0 for activating the firewalling" >&2 -fi diff --git a/scripts/remove b/scripts/remove index 1d92f61..1ba32f2 100644 --- a/scripts/remove +++ b/scripts/remove @@ -1,27 +1,40 @@ #!/bin/bash -# VPN Client app for YunoHost +# VPN Client app for YunoHost # Copyright (C) 2015 Julien Vaubourg # Contribute at https://github.com/labriqueinternet/vpnclient_ynh -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -source ./helpers +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= -# Retrieve arguments -domain=$(sudo yunohost app setting vpnclient domain) +source _common.sh +source /usr/share/yunohost/helpers +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) + +#================================================= # The End ynh_systemctl stop ynh-vpnclient-checker.service sudo systemctl disable ynh-vpnclient-checker.service @@ -50,4 +63,3 @@ sudo systemctl reload nginx # Remove sources sudo rm -rf /var/www/vpnadmin/ -exit 0 diff --git a/scripts/restore b/scripts/restore index 7b88ea1..aa987d8 100644 --- a/scripts/restore +++ b/scripts/restore @@ -1,5 +1,24 @@ #!/bin/bash +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +if [ ! -e _common.sh ]; then + # Fetch helpers file if not in current directory + cp ../settings/scripts/_common.sh ./_common.sh + chmod a+rx _common.sh +fi +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + backup_dir="${1}/apps/vpnclient" sudo mkdir -p /etc/openvpn/ @@ -18,4 +37,3 @@ bash ./upgrade sudo rm -r "${tmpdir}/" -exit 0 diff --git a/scripts/upgrade b/scripts/upgrade index 6d4dd7b..cf2a1c8 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -1,18 +1,41 @@ #!/bin/bash -ynh_setting() { - app=${1} - setting=${2} +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= - sudo grep "^${setting}:" "/etc/yunohost/apps/${app}/settings.yml" | sed s/^[^:]\\+:\\s*[\"\']\\?// | sed s/\\s*[\"\']\$// -} +source _common.sh +source /usr/share/yunohost/helpers -source ./helpers -source ./prerequisites +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) +path_url=$(ynh_app_setting_get $app path) +is_public=$(ynh_app_setting_get $app is_public) +final_path=$(ynh_app_setting_get $app final_path) +server_name=$(ynh_app_setting_get $app server_name) + +#================================================= +# CHECK VERSION +#================================================= + +ynh_abort_if_up_to_date + +#================================================= -domain=$(ynh_setting vpnclient domain) -path=$(ynh_setting vpnclient path) -server_name=$(ynh_setting vpnclient server_name) sudo mkdir -m 0700 -p /var/cache/labriqueinternet/vpnclient/ sudo tar czf "/var/cache/labriqueinternet/vpnclient/rollback_$(date +%Y-%m-%d-%H%M%S).tgz" /etc/openvpn/ /etc/yunohost/apps/vpnclient/ &> /dev/null @@ -44,4 +67,3 @@ fi ynh_systemctl start ynh-vpnclient -exit 0