Browse Source

[enh] New config panel + support .ovpn file

ljf 3 years ago
parent
commit
2c7c4f8cc2
5 changed files with 284 additions and 241 deletions
  1. 27 12
      conf/hook_post-iptable-rules
  2. 36 82
      conf/ynh-vpnclient
  3. 67 108
      config_panel.toml
  4. 148 39
      scripts/config
  5. 6 0
      scripts/install

+ 27 - 12
conf/hook_post-iptable-rules

@@ -1,7 +1,20 @@
 #!/bin/bash
 
-host6=$(dig AAAA +short <TPL:SERVER_NAME> | grep -v '\.$')
-host4=$(dig A +short <TPL:SERVER_NAME> | grep -v '\.$')
+server_names=$(grep -o -P '^\s*remote\s+\K([^\s]+)' /etc/openvpn/client.conf | sort | uniq)
+host6=$(dig AAAA +short $server_names | grep -v '\.$')
+host4=$(dig A +short $server_names | grep -v '\.$')
+
+# In case an ip has been provided in ovpn conf
+for i in ${server_names}; do
+  if [[ "${i}" =~ : ]]; then
+      host6+=" ${i}"
+  elif [[ "${i}" =~ ^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$ ]]; then
+      host4+=" ${i}"
+  fi
+done
+
+interface=$(ip route | awk '/default via/ { print $NF; }')
+dns=$(grep -o -P '\s*nameserver\s+\K[ABCDEFabcdef\d.:]+' /etc/resolv.dnsmasq.conf)
 
 # IPv6
 
@@ -18,11 +31,12 @@ sudo ip6tables -w -A vpnclient_in -j DROP
 
 if [ ! -z "${host6}" ]; then
   for i in ${host6}; do
-    sudo ip6tables -w -A vpnclient_out -d "${i}" -p <TPL:PROTO> --dport <TPL:SERVER_PORT> -j ACCEPT
+    sudo ip6tables -w -A vpnclient_out -d "${i}" -j ACCEPT
   done
 fi
 
-for i in <TPL:DNS0> <TPL:DNS1>; do
+for i in ${dns};
+do
   if [[ "${i}" =~ : ]]; then
     sudo ip6tables -w -A vpnclient_out -p udp -d "${i}" --dport 53 -j ACCEPT
   fi
@@ -35,9 +49,9 @@ sudo ip6tables -w -A vpnclient_out -j DROP
 
 sudo ip6tables -w -A vpnclient_fwd -j DROP
 
-sudo ip6tables -w -I INPUT 1 -i <TPL:WIRED_DEVICE> -j vpnclient_in
-sudo ip6tables -w -I OUTPUT 1 -o <TPL:WIRED_DEVICE> -j vpnclient_out
-sudo ip6tables -w -I FORWARD 1 -o <TPL:WIRED_DEVICE> -j vpnclient_fwd
+sudo ip6tables -w -I INPUT 1 -i $interface -j vpnclient_in
+sudo ip6tables -w -I OUTPUT 1 -o $interface -j vpnclient_out
+sudo ip6tables -w -I FORWARD 1 -o $interface -j vpnclient_fwd
 
 # IPv4
 
@@ -54,11 +68,12 @@ sudo iptables -w -A vpnclient_in -j DROP
 
 if [ ! -z "${host4}" ]; then
   for i in ${host4}; do
-    sudo iptables -w -A vpnclient_out -d "${i}" -p <TPL:PROTO> --dport <TPL:SERVER_PORT> -j ACCEPT
+    sudo iptables -w -A vpnclient_out -d "${i}" -j ACCEPT
   done
 fi
 
-for i in <TPL:DNS0> <TPL:DNS1>; do
+for i in ${dns};
+do
   if [[ "${i}" =~ \. ]]; then
     sudo iptables -w -A vpnclient_out -p udp -d "${i}" --dport 53 -j ACCEPT
   fi
@@ -71,8 +86,8 @@ sudo iptables -w -A vpnclient_out -j DROP
 
 sudo iptables -w -A vpnclient_fwd -j DROP
 
-sudo iptables -w -I INPUT 1 -i <TPL:WIRED_DEVICE> -j vpnclient_in
-sudo iptables -w -I OUTPUT 1 -o <TPL:WIRED_DEVICE> -j vpnclient_out
-sudo iptables -w -I FORWARD 1 -o  <TPL:WIRED_DEVICE> -j vpnclient_fwd
+sudo iptables -w -I INPUT 1 -i $interface -j vpnclient_in
+sudo iptables -w -I OUTPUT 1 -o $interface -j vpnclient_out
+sudo iptables -w -I FORWARD 1 -o  $interface -j vpnclient_fwd
 
 exit 0

+ 36 - 82
conf/ynh-vpnclient

@@ -65,7 +65,7 @@ has_ip6delegatedprefix() {
 }
 
 is_ip6addr_set() {
-  ip address show dev tun0 2> /dev/null | grep -q "${ynh_ip6_addr}/128"
+  ip address show dev tun0 2> /dev/null | grep -q "${ynh_ip6_addr}/"
 }
 
 set_ip6addr() {
@@ -83,32 +83,41 @@ unset_ip6addr() {
 #
 
 is_serverip6route_set() {
-  server_ip6=${1}
+  server_ip6s=${1}
 
   if [ -z "${server_ip6}" ]; then
     false
   else
-    ip -6 route | grep -q "${server_ip6}/"
+    for server_ip6 in ${server_ip6s};
+    do
+        ip -6 route | grep -q "${server_ip6}/" || return 1
+    done
   fi
 }
 
 set_serverip6route() {
-  server_ip6=${1}
+  server_ip6s=${1}
   ip6_gw=${2}
   wired_device=${3}
 
   info "Adding IPv6 server route"
-  ip route add "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
+    for server_ip6 in ${server_ip6s};
+    do
+        ip route add "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
+    done
 }
 
 
 unset_serverip6route() {
-  server_ip6=${1}
+  server_ip6s=${1}
   ip6_gw=${2}
   wired_device=${3}
 
   info "Removing IPv6 server route"
-  ip route delete "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
+    for server_ip6 in ${server_ip6s};
+    do
+        ip route delete "${server_ip6}/128" via "${ip6_gw}" dev "${wired_device}"
+    done
 }
 
 
@@ -131,11 +140,11 @@ is_hotspot_knowme() {
 ###################################################################################
 
 is_dns_set() {
-  # FIXME : having the ynh_dns0 in the resolv.dnsmasq.conf is not necessarily good enough
-  # We want it to be the only one (with ynh_dns1) but nowadays for example ARN's resolver is
-  # in the default list from yunohost...
+  
+  current_dns=$(grep -o -P '\s*nameserver\s+\K[ABCDEFabcdef\d.:]+' /etc/resolv.dnsmasq.conf | sort | uniq)
+  wanted_dns=$(echo "${ynh_dns}" | sort | uniq)
   [ -e /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient ]\
-  && ( grep -q ${ynh_dns0} /etc/resolv.conf || grep -q ${ynh_dns0} /etc/resolv.dnsmasq.conf )
+  && [[ "$current_dns" == "wanted_dns" ]]
 }
 
 set_dns() {
@@ -147,8 +156,7 @@ set_dns() {
   cp -fa "${resolvconf}" "${resolvconf}.ynh"
 
   cat << EOF > /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient
-echo nameserver ${ynh_dns0} > ${resolvconf}
-echo nameserver ${ynh_dns1} >> ${resolvconf}
+echo "${ynh_dns}" | sed 's/,/\n/g' | sort | uniq | sed 's/^/nameserver /g' > ${resolvconf}
 EOF
 
   bash /etc/dhcp/dhclient-exit-hooks.d/ynh-vpnclient
@@ -173,7 +181,7 @@ unset_dns() {
 ###################################################################################
 
 is_firewall_set() {
-  wired_device=${1}
+  wired_device=$(ip route | awk '/default via/ { print $NF; }')
 
   ip6tables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}"\
   && iptables -w -nvL OUTPUT | grep vpnclient_out | grep -q "${wired_device}"
@@ -182,17 +190,8 @@ is_firewall_set() {
 set_firewall() {
   info "Adding vpnclient custom rules to the firewall"
 
-  wired_device=${1}
-
   cp /etc/yunohost/hooks.d/{90-vpnclient.tpl,post_iptable_rules/90-vpnclient}
 
-  sed "s|<TPL:SERVER_NAME>|${ynh_server_name}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-  sed "s|<TPL:SERVER_PORT>|${ynh_server_port}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-  sed "s|<TPL:PROTO>|${ynh_server_proto}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-  sed "s|<TPL:WIRED_DEVICE>|${wired_device}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-  sed "s|<TPL:DNS0>|${ynh_dns0}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-  sed "s|<TPL:DNS1>|${ynh_dns1}|g" -i /etc/yunohost/hooks.d/post_iptable_rules/90-vpnclient
-
   info "Restarting yunohost firewall..."
   yunohost firewall reload && success "Firewall restarted!"
 }
@@ -240,54 +239,12 @@ is_openvpn_running() {
 
 start_openvpn() {
 
-  ip6_gw=${1}
-  server_ip6=${2}
-
-  if [ ! -z "${ip6_gw}" -a ! -z "${server_ip6}" ]; then
-    proto=udp6
-    [ "${ynh_server_proto}" == tcp ] && proto=tcp6-client
-  else
-    proto=udp
-    [ "${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
 
-  info "Preparing openvpn configuration..."
-  cp /etc/openvpn/client.conf{.tpl,}
-
-  sed "s|<TPL:SERVER_NAME>|${ynh_server_name}|g" -i /etc/openvpn/client.conf
-  sed "s|<TPL:SERVER_PORT>|${ynh_server_port}|g" -i /etc/openvpn/client.conf
-  sed "s|<TPL:PROTO>|${proto}|g" -i /etc/openvpn/client.conf
-
-  if [ -e /etc/openvpn/keys/user.key ]; then
-    sed 's|^<TPL:CERT_COMMENT>||' -i /etc/openvpn/client.conf
-  else
-    sed 's|^<TPL:CERT_COMMENT>|;|' -i /etc/openvpn/client.conf
-  fi
-
-  if [ -e /etc/openvpn/keys/user_ta.key ]; then
-    sed 's|^<TPL:TA_COMMENT>||' -i /etc/openvpn/client.conf
-  else
-    sed 's|^<TPL:TA_COMMENT>|;|' -i /etc/openvpn/client.conf
-  fi
-
-  if [[ "${proto}" =~ udp ]]; then
-    sed 's|^<TPL:UDP_COMMENT>||' -i /etc/openvpn/client.conf
-  else
-    sed 's|^<TPL:UDP_COMMENT>|;|' -i /etc/openvpn/client.conf
-  fi
-
-  if [ -z "${ynh_login_user}" ]; then
-    sed 's|^<TPL:LOGIN_COMMENT>|;|' -i /etc/openvpn/client.conf
-  else
-    sed 's|^<TPL:LOGIN_COMMENT>||' -i /etc/openvpn/client.conf
-  fi
-
   info "Now actually starting OpenVPN client..."
   systemctl start openvpn@client.service
 
@@ -339,6 +296,7 @@ ynh_setting_get() {
   setting=${2}
 
   grep "^${setting}:" "/etc/yunohost/apps/${app}/settings.yml" | sed s/^[^:]\\+:\\s*[\"\']\\?// | sed s/\\s*[\"\']\$//
+  # '"
 }
 
 ynh_setting_set() {
@@ -380,13 +338,8 @@ if [ "$1" != restart ]; then
   info "Retrieving Yunohost settings... "
 
   ynh_service_enabled=$(ynh_setting_get vpnclient service_enabled)
-  ynh_server_name=$(ynh_setting_get vpnclient server_name)
-  ynh_server_port=$(ynh_setting_get vpnclient server_port)
-  ynh_server_proto=$(ynh_setting_get vpnclient server_proto)
   ynh_ip6_addr=$(ynh_setting_get vpnclient ip6_addr)
-  ynh_login_user=$(ynh_setting_get vpnclient login_user)
-  ynh_dns0=$(ynh_setting_get vpnclient dns0)
-  ynh_dns1=$(ynh_setting_get vpnclient dns1)
+  ynh_dns=$(ynh_setting_get vpnclient nameservers)
 
   old_ip6_gw=$(ynh_setting_get vpnclient ip6_gw)
   old_wired_device=$(ynh_setting_get vpnclient wired_device)
@@ -394,12 +347,13 @@ if [ "$1" != restart ]; then
 
   new_ip6_gw=$(ip -6 route | grep default\ via | awk '{ print $3 }')
   new_wired_device=$(ip route | awk '/default via/ { print $NF; }')
-  new_server_ip6=$(host "${ynh_server_name}" 2> /dev/null | awk '/IPv6/ { print $NF; }')
-
-  if [ -z "${new_server_ip6}" ]; then
-    # FIXME wtf is this hardcoded IP ...
-    new_server_ip6=$(host "${ynh_server_name}" 80.67.188.188 2> /dev/null | awk '/IPv6/ { print $NF; }')
-  fi
+  ynh_server_names=$(grep -o -P '^\s*remote\s+\K([^\s]+)' /etc/openvpn/client.conf | sort | uniq)
+  new_server_ip6=$(dig AAAA +short $ynh_server_names | grep -v '\.$' | sort | uniq)
+  for i in $ynh_server_names; do
+    if [[ "${i}" =~ : ]] && [[ ! "$new_server_ip6" == *"${i}"* ]] ; then
+        new_server_ip6+=" ${i}"
+    fi
+  done
 
   success "Settings retrieved"
 
@@ -438,7 +392,7 @@ case "${1}" in
     then
       info "(openvpn is already running)"
     else
-      start_openvpn "${new_ip6_gw}" "${new_server_ip6}"
+      start_openvpn
     fi
 
     # Check old state of the server ipv6 route
@@ -469,9 +423,9 @@ case "${1}" in
     fi
 
     # Set ipv6/ipv4 firewall
-    if ! is_firewall_set "${new_wired_device}"
+    if ! is_firewall_set
     then
-      set_firewall "${new_wired_device}"
+      set_firewall
     fi
 
     # Update dynamic settings
@@ -505,7 +459,7 @@ case "${1}" in
       unset_serverip6route "${old_server_ip6}" "${old_ip6_gw}" "${old_wired_device}"
     fi
 
-    is_firewall_set "${old_wired_device}" && unset_firewall
+    is_firewall_set && unset_firewall
 
     is_dns_set && unset_dns
 
@@ -578,7 +532,7 @@ case "${1}" in
       info "No IPv6 server route to set"
     fi
 
-    if is_firewall_set "${new_wired_device}"; then
+    if is_firewall_set; then
       success "IPv6/IPv4 firewall set"
     else
       info "No IPv6/IPv4 firewall set"

+ 67 - 108
config_panel.toml

@@ -1,148 +1,107 @@
-version = "0.1"
-name = "VPN Client configuration panel"
+version = "1.0"
 
 [main]
 name = "Auto-configuration"
 
-    [main.cube]
+    [main.vpn]
     name = ""
         
-        [main.cube.warning]
-        ask = "To configure your vpn client, the use of a VPN supporting the .cube file is recommended."
-        type = "warning"
+        [main.vpn.status]
+        ask = "The status of your VPN is unknown."
+        type = "alert"
+        style = "info"
         
-        [main.cube.service_enabled]
+        [main.vpn.doc]
+        ask = "Only VPN with a dedicated public ip that accept input traffic are compatible. See the compatible providers list."
+        type = "warning"
+
+        [main.vpn.service_enabled]
         ask = "Enable VPN"
         type = "boolean"
-        default = 0
         help = "If you disable, your VPN will not run even if you restart your server"
-
-        [main.cube.cube_file]
-        ask = "Load a cube File"
-        type = "file"
-        optional = true
-        default = ""
-        accept = ".cube"
-        helpLink = { href = "https://labriqueinter.net/dotcubefiles.html", text = "Info about cube file format" }
-        
-[manual]
-name = "Manual configuration"
-
-    [manual.vpn]
-    name = "VPN"
-        
-        [manual.vpn.warning]
-        ask = "If you have not a .cube file you can configure your VPN manually.<br/>IMPORTANT: this app only supports fixed and dedicated public ip VPNs."
-        helpLink = { href = "https://labriqueinter.net/dotcubefiles.html", text = "See the list of public ip vpn providers" }
-        type = "warning"
-
         
-        [manual.vpn.server_name]
-        ask = "Server address"
-        type = "string"
-        default = ""
-        optional = true
-        pattern = "^[^/ ]*$"
-        help = "Prefer to put directly the IP address of your VPN server here instead of domain name"
-        
-        [manual.vpn.server_port]
-        ask = "Server Port"
-        type = "number"
-        default = "1194"
-        min = 1
-        max = 65535
-        help = "Default openvpn port is 1194. If your server is connected to a restricted network and if your VPN provider support it, set 443 should work better."
-        
-        [manual.vpn.server_proto]
-        ask = "Protocol"
-        choices = ["udp", "tcp"]
-        default = "udp"
-        help = "UDP is preferred for performance reason. If your server is connected to a restricted network, and UDP does not work, try with TCP."
-        
-        [manual.vpn.ip4_addr]
-        ask = "IPv4"
-        type = "string"
-        default = ""
-        example = "141.125.36.75"
+        [main.vpn.config_file]
+        ask = "Configuration file"
+        type = "file"
+        accept = [".cube", ".ovpn", ".conf"]
+        help = ".cube file recommended, .ovpn file accepted"
+        bind = "/etc/openvpn/client.conf"
         
-        [manual.vpn.ip6_net]
-        ask = "Delegated prefix (IPv6)"
-        type = "string"
-        default = ""
-        optional = true
-        example = "2001:db8:42::"
-        pattern = "^[0-9a-fA-F:]+$"
-
-    [manual.auth]
+    [main.auth]
     name = "Authentication"
-        
-        [manual.auth.crt_server_ca]
+
+        [main.auth.crt_server_ca]
         ask = "Update Server CA"
         type = "file"
-        default = ""
         help = "You should upload a CA certificate to start"
-        source="/etc/openvpn/keys/ca-server.crt"
+        bind="/etc/openvpn/keys/ca-server.crt"
+        visible = "! match(config_file,'^\s*<ca>')"
         
-        [manual.auth.crt_client]
+        [main.auth.crt_client]
         ask = "Update Client Certificate"
         type = "file"
-        default = ""
         optional = true
-        source="/etc/openvpn/keys/user.crt"
+        bind="/etc/openvpn/keys/user.crt"
+        visible = "match(config_file,'^\s*crt\s') && ! match(config_file,'^\s*<crt>')"
         
-        [manual.auth.crt_client_key]
+        [main.auth.crt_client_key]
         ask = "Update Client Key"
         type = "file"
-        default = ""
         help = "This file begins with -----BEGIN PRIVATE KEY-----"
         optional = true
-        example = "-----BEGIN PRIVATE KEY-----"
-        source="/etc/openvpn/keys/user.key"
-        
-        [manual.auth.crt_client_ta]
-        ask = "Upload Shared-Secret"
-        type = "file"
-        default = ""
-        optional = true
-        example = "ta.key"
-        source="/etc/openvpn/keys/user_ta.key"
+        bind="/etc/openvpn/keys/user.key"
+        visible = "match(config_file,'^\s*key\s') && ! match(config_file,'^\s*<key>')"
         
-        [manual.auth.login_user]
+        [main.auth.login_user]
         ask = "Username"
         type = "string"
-        default = ""
         example = "camille"
         optional = true
-        pattern = "^[^/ ]+$"
+        pattern = "^[a-zA-Z_-\.@]+$"
+        visible = "match(config_file,'^\s*auth-user-pass\s')"
         
-        [manual.auth.login_passphrase]
+        [main.auth.login_passphrase]
         ask = "Password"
         type = "password"
-        default = ""
-        visibleif = "login_user"
-
-    [manual.dns]
+        optional = true
+        visible = "match(config_file,'^\s*auth-user-pass\s')"
+        
+        [main.auth.crt_client_ta]
+        ask = "TLS Auth shared secret"
+        type = "file"
+        optional = true
+        example = "ta.key"
+        help = "Some servers have an additional protection agains Deny of Service attack. If you have no tls-auth key in your ovpn, skip this question."
+        bind="/etc/openvpn/keys/user_ta.key"
+        visible = "match(config_file,'^\s*tls-auth\s') && ! match(config_file,'^\s*<tls-auth>')"
+        
+[advanced]
+name = "DNS & IPv6"
+    [advanced.dns]
     name = "DNS"
 
-        [manual.dns.dns0]
-        ask = "First resolver"
-        type = "string"
-        default = "89.234.141.66"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+        [advanced.dns.dns_method]
+        ask = "DNS provider"
+        type = "select"
+        choices.pushed = "Use DNS from my VPN provider"
+        choices.yunohost = "Keep DNS from YunoHost"
+        choices.custom = "Use custom DNS"
 
-        [manual.dns.dns1]
-        ask = "Second resolver"
-        type = "string"
-        default = "2a00:5881:8100:1000::3"
+        [advanced.dns.nameservers]
+        ask = "DNS resolvers"
+        type = "tags"
         optional = true
+        visible = "dns_method == 'custom'"
         pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+        
+    [advanced.ipv6]
+    name = "IPv6"
 
-    [manual.advanced]
-    name = "Advanced configuration"
-
-        [manual.advanced.ovpn]
-        ask = "OVPN template"
-        type = "text"
+        [advanced.ipv6.ip6_addr]
+        ask = "IPv6"
+        type = "string"
         optional = true
-        source="/etc/openvpn/client.conf.tpl"
+        example = "2001:db8:42::2"
+        help = "If ipv6 address is not pushed directly by your openvpn server, you can indicate a specific ip to use."
+        pattern.regexp = "^[0-9a-fA-F:]+$"
+        pattern.error = "Please provide a valid IPv6"

+ 148 - 39
scripts/config

@@ -31,9 +31,34 @@ final_path=$(ynh_app_setting_get $app final_path)
 get__status() {
     if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ]
     then
-        echo "running"
+        if [ $old[service_enabled] -eq 1 ]
+        then
+            cat << EOF
+style: success
+ask:
+  en: Your VPN is running :)
+EOF
+        else
+            cat << EOF
+style: warning
+ask:
+  en: Your VPN is running, but it shouldn't !
+EOF
+        fi
+    elif [ $old[service_enabled] -eq 1 ]
+    then
+        cat << EOF
+style: danger
+ask:
+  en: Your VPN is down !
+EOF
     else
-        echo "not running"
+        cat << EOF
+style: info
+ask:
+  en: Your VPN is down has expected.
+EOF
+
     fi
 }
 
@@ -56,40 +81,65 @@ get__login_passphrase() {
 # SPECIFIC VALIDATORS FOR TOML SHORT KEYS
 #=================================================
 validate__login_user() {
-    [[ -n "${new[login_passphrase]}" && -z "${new[login_user]}" ]] &&
-        echo 'A Username is needed when you suggest a Password'
+
+    if grep -q '^\s*auth-user-pass' ${config_file}
+    then
+        [[ -z "${login_user}" ]] &&
+            echo 'A Username is needed with this configuration file'
+    fi
 }
 
 validate__login_passphrase() {
-    [[ -n "${new[login_user]}" && -z "${new[login_passphrase]}" ]] &&
-        echo 'A Password is needed when you suggest a Username'
+    if grep -q '^\s*auth-user-pass' ${config_file}
+    then
+        [[ -z "${login_passphrase}" ]] &&
+            echo 'A Password is needed with this configuration file'
+    fi
 }
 
-validate__crt() {
-    [[ -n "${new[key]}" && -z "${new[crt]}" ]] &&
-        echo "A Client Certificate is needed when you suggest a Key"
+validate__crt_server_ca() {
+    if grep -q '^\s*ca\s' ${config_file}
+    then
+        [[ ! -e "${crt_server_ca}" ]] &&
+            echo "A server CA certificate is needed"
+    fi
 }
 
-validate__key() {
-    [[ -n "${new[crt]}" && -z "${new[key]}" ]] &&
-        echo "A Key is needed when you suggest a Client Certificate"
+validate__crt_client() {
+    if grep -q '^\s*cert\s' ${config_file}
+    then
+        [[ ! -e "${crt_client}" ]] &&
+            echo "A Client certificate is needed with this configuration file"
+    fi
 }
 
-# TODO
-validate__ip6_net() {
-    if [[ -z "${new[ip6_net]}" ]]
-    then 
-        echo 'The IPv6 Delegated Prefix is empty'
+validate__crt_client_key() {
+    if grep -q '^\s*key\s' ${config_file}
+    then
+        [[ ! -e "${crt_client_key}" ]] &&
+            echo "A client private key is needed with this configuration file"
     fi
 }
 
+validate__crt_client_ta() {
+    if grep -q '^\s*tls-auth\s' ${config_file}
+    then
+        [[ ! -e "${crt_client_ta}" ]] &&
+            echo "A TLS auth shared secret is needed with this configuration file"
+    fi
+}
+
+validate__nameservers() {
+    [[ "$dns_method" == "custom" ]] && [[ -z "$nameservers" ]]
+        echo "You need to choose DNS resolvers or select an other method to provide DNS resolvers"
+}
 #=================================================
 # SPECIFIC SETTERS FOR TOML SHORT KEYS
 #=================================================
 set__login_user() {
-    if [ -z "${new[login_user]}" ]
+    if [ -n "${login_user}" ]
     then
-        echo "${new[login_user]}\n${new[login_passphrase]}" > /etc/openvpn/keys/credentials 
+        echo "${login_user}\n${login_passphrase}" > /etc/openvpn/keys/credentials 
     else
         echo "" > /etc/openvpn/keys/credentials
     fi
@@ -99,28 +149,19 @@ set__login_passphrase() {
     :
 }
 
-# TODO
-set__cube_file() {
-    if [ -f "${new[cube_file]}" ]
-    then
-        cp -f $tmp_dir/client.conf.tpl /etc/openvpn/client.conf.tpl
-    fi
-}
-
 #=================================================
 # OVERWRITING VALIDATE STEP 
 #=================================================
 ynh_panel_validate() {
-    set +x 
+    tmp_dir=$(dirname "${config_file}")
     # Overwrite form response with cube files data before validation process
-    if [ -f "${new[cube_file]}" ]
+    if [ -f "${config_file}" ] && [[ $config_file == *.cube ]]
     then
         declare -A settings
         settings[server_name]=""
         settings[server_port]=""
         settings[server_proto]=""
         settings[ip6_net]=""
-        settings[ip4_addr]=""
         settings[login_user]=""
         settings[login_passphrase]=""
         settings[dns0]=""
@@ -130,27 +171,30 @@ ynh_panel_validate() {
         settings[crt_client_key]="file"
         settings[crt_client_ta]="file"
 
-        tmp_dir=$(dirname "${new[cube_file]}")
         for setting_name in "${!settings[@]}"
         do
-            setting_value="$(jq --raw-output ".$setting_name" "${new[cube_file]}")"
+            setting_value="$(jq --raw-output ".$setting_name" "${config_file}")"
             if [[ "$setting_value" == "null" ]]
             then
                 setting_value=''
             # Save file in tmp dir
             elif [[ "${settings[$setting_name]}" == "file" ]]
             then
-                echo "${settings[$setting_name]}" | sed 's/|/\n/g' > $tmp_dir/$setting_name
-                setting_value="$tmp_dir/$setting_name"
+                if [ -n "${settings_value}" ]
+                then
+                    echo "${setting_value}" | sed 's/|/\n/g' > $tmp_dir/$setting_name
+                    setting_value="$tmp_dir/$setting_name"
+                fi
             fi
 
-            new[$setting_name]="$setting_value"
+            $setting_name="$setting_value"
         done
-        
+        dns_method="custom"
+        nameservers="$dns0,$dns1" 
         # Build specific OVPN template
         cp -f /etc/openvpn/client.conf.tpl.restore $tmp_dir/client.conf.tpl
         # Remove some lines
-        for rm_regex in "$(jq --raw-output '.openvpn_rm[]' "${new[cube_file]}")"
+        for rm_regex in "$(jq --raw-output '.openvpn_rm[]' "${config_file}")"
         do
             if [ ! -z "${rm_regex}" ] ; then
                 sed -i "/$rm_regex/di" $tmp_dir/client.conf.tpl
@@ -159,10 +203,75 @@ ynh_panel_validate() {
 
         # Add some other lines
         echo "# Custom" >> $tmp_dir/client.conf.tpl
-        jq --raw-output ".openvpn_add[]" "${new[cube_file]}" >> $tmp_dir/client.conf.tpl
+        jq --raw-output ".openvpn_add[]" "${config_file}" >> $tmp_dir/client.conf.tpl
+
+        # Build directly the OVPN file
+        cp /etc/openvpn/client.conf.tpl "${config_file}"
+        sed "s|<TPL:SERVER_NAME>|${settings[server_name]}|g" -i "${config_file}"
+        sed "s|<TPL:SERVER_PORT>|${settings[server_port]}|g" -i "${config_file}"
+        sed "s|<TPL:PROTO>|${settings[server_proto]}|g" -i "${config_file}"
+        if [ -e "${settings[crt_client_key]}" ]; then
+            sed 's|^<TPL:CERT_COMMENT>||g' -i "${config_file}"
+        else
+            sed 's|^<TPL:CERT_COMMENT>|;|g' -i "${config_file}"
+        fi
+        if [ -e "${settings[crt_client_ta]}" ]; then
+            sed 's|^<TPL:TA_COMMENT>||' -i "${config_file}"
+        else
+            sed 's|^<TPL:TA_COMMENT>|;|' -i "${config_file}"
+        fi
+        if [[ "${settings[server_proto]}" =~ udp ]]; then
+            sed 's|^<TPL:UDP_COMMENT>||' -i "${config_file}"
+        else
+            sed 's|^<TPL:UDP_COMMENT>|;|' -i "${config_file}"
+        fi
+        if [ -n "${settings[login_user]}" ]; then
+            sed 's|^<TPL:LOGIN_COMMENT>||' -i "${config_file}"
+        else
+            sed 's|^<TPL:LOGIN_COMMENT>|;|' -i "${config_file}"
+        fi
+
+
+    elif [ -f "${config_file}" ] && [[ "${config_file}" =~ ^.*\.(ovpn|conf)$ ]]
+    then
+        if grep -q '^\s*<ca>' ${config_file}
+        then
+            grep -Poz '(?<=<ca>)(.*\n)*.*(?=</ca>)' ${config_file} > $tmp_dir/crt_server_ca
+            crt_server_ca=$tmp_dir/crt_server_ca
+            sed -i '/^\s*<ca>/,/\s*<\/ca>/d' ${config_file}
+            sed -i '/^\s*ca\s/d' ${config_file}
+            echo "ca /etc/openvpn/keys/ca-server.crt" >> ${config_file}
+        fi
+        if grep -q '^\s*<cert>' ${config_file}
+        then
+            grep -Poz '(?<=<cert>)(.*\n)*.*(?=</cert>)' ${config_file} > $tmp_dir/crt_client
+            crt_client=$tmp_dir/crt_client
+            sed -i '/^\s*<cert>/,/\s*<\/cert>/d' ${config_file}
+            sed -i '/^\s*cert\s/d' ${config_file}
+            echo "cert /etc/openvpn/keys/user.crt" >> ${config_file}
+        fi
+        if grep -q '^\s*<key>' ${config_file}
+        then
+            grep -Poz '(?<=<key>)(.*\n)*.*(?=</key>)' ${config_file} > $tmp_dir/crt_client_key
+            crt_client_key=$tmp_dir/crt_client_key
+            sed -i '/^\s*<key>/,/\s*<\/key>/d' ${config_file}
+            sed -i '/^\s*key\s/d' ${config_file}
+            echo "key /etc/openvpn/keys/user.key" >> ${config_file}
+        fi
+        if grep -q '^\s*<tls-auth>' ${config_file}
+        then
+            grep -Poz '(?<=<tls-auth>)(.*\n)*.*(?=</tls-auth>)' ${config_file} > $tmp_dir/crt_client_ta
+            crt_client_ta=$tmp_dir/crt_client_ta
+            sed -i '/^\s*<tls-auth>/,/\s*<\/tls-auth>/d' ${config_file}
+            sed -i '/^\s*tls-auth\s/d' ${config_file}
+            echo "tls-auth /etc/openvpn/keys/user_ta.key 1" >> ${config_file}
+        fi
+        sed -i 's@^\s*ca\s.*$@ca /etc/openvpn/keys/ca-server.crt@g' ${config_file}
+        sed -i 's@^\s*cert\s.*$@cert /etc/openvpn/keys/user.crt@g' ${config_file}
+        sed -i 's@^\s*key\s.*$@key /etc/openvpn/keys/user.key@g' ${config_file}
+        sed -i 's@^\s*tls-auth\s.*$@tls-auth /etc/openvpn/keys/user-ta.key@g' ${config_file}
     fi
 
-    set -x
     _ynh_panel_validate
 }
 

+ 6 - 0
scripts/install

@@ -62,6 +62,12 @@ ynh_script_progression "Storing installation settings..."
 ynh_app_setting_set "$app" domain "$domain"
 ynh_app_setting_set "$app" final_path "$final_path"
 
+# Default values for config panel
+ynh_app_setting_set "$app" service_enabled 0
+ynh_app_setting_set "$app" dns_method "pushed"
+ynh_app_setting_set "$app" nameservers ""
+ynh_app_setting_set "$app" ip6_addr ""
+
 #=================================================
 # STANDARD MODIFICATIONS
 #=================================================