Parcourir la source

Merge pull request #2 from jvaubourg/dev

New version of Hotspot, available only with a version of YunoHost using dnsmasq (not stable for now)
Julien Vaubourg il y a 10 ans
Parent
commit
7cb106adda

+ 12 - 2
README.md

@@ -18,7 +18,17 @@ See the <a href="https://raw.githubusercontent.com/jvaubourg/hotspot_ynh/master/
 * WPA2 encryption
 * 802.11n compliant
 * IPv6 compliant (with a delegated prefix)
-* Automatic clients configuration (IPv6 and IPv4)
-* Announce DNS resolvers (IPv6 and IPv4)
+* Announce DNS resolvers (IPv6 with RDNSS/DHCPv6 and IPv4 with DHCPv4)
+* Automatic clients configuration (IPv6 with SLAAC/DHCPv6 and IPv4 with DHCPv4)
 * Set an IPv6 from your delegated prefix (*prefix::42*) on the server, to use for the AAAA records
 * Web interface ([screenshot](https://raw.githubusercontent.com/jvaubourg/hotspot_ynh/master/screenshot.png))
+
+## Prerequisites
+
+This app works with a non-stable version of YunoHost.
+
+Until this version is available (coming soon!) as an official stable release, you need to execute some commands before installing this app:
+
+    # service bind9 stop
+    # update-rc.d bind9 remove
+    # apt-get install dnsmasq

+ 0 - 1
TODO

@@ -1,2 +1 @@
 * Translate PHP interface in French
-* Add license headers

+ 0 - 15
conf/dhcpd.conf.tpl

@@ -1,15 +0,0 @@
-option domain-name-servers <TPL:IP4_DNS0>, <TPL:IP4_DNS1>;
-default-lease-time 14440;
-ddns-update-style none;
-deny bootp;
-
-shared-network <TPL:WIFI_DEVICE> {
-  subnet <TPL:IP4_NAT_PREFIX>.0
-  netmask 255.255.255.0 {
-    option routers <TPL:IP4_NAT_PREFIX>.1;
-    option subnet-mask 255.255.255.0;
-    pool {
-      range <TPL:IP4_NAT_PREFIX>.2 <TPL:IP4_NAT_PREFIX>.254;
-    }
-  }
-}

+ 47 - 0
conf/dnsmasq_dhcpdv4.conf.tpl

@@ -0,0 +1,47 @@
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
+# Do DHCP for this subnet.
+dhcp-range=interface:<TPL:WIFI_DEVICE>,<TPL:IP4_NAT_PREFIX>.2,<TPL:IP4_NAT_PREFIX>.254,4h
+
+# Send DHCPv4 option.
+dhcp-option=option:dns-server,<TPL:IP4_DNS0>,<TPL:IP4_DNS1>
+
+# Set the DHCP server to authoritative mode. In this mode it will barge in
+# and take over the lease for any client which broadcasts on the network,
+# whether it has a record of the lease or not. This avoids long timeouts
+# when a machine wakes up on a new network. DO NOT enable this if there's
+# the slightest chance that you might end up accidentally configuring a DHCP
+# server for your campus/company accidentally. The ISC server uses
+# the same option, and this URL provides more information:
+# http://www.isc.org/files/auth.html
+dhcp-authoritative
+
+# On systems which support it, dnsmasq binds the wildcard address,
+# even when it is listening on only some interfaces. It then discards
+# requests that it shouldn't reply to. This has the advantage of
+# working even when interfaces come and go and change address. If you
+# want dnsmasq to really bind only the interfaces it is listening on,
+# uncomment this option. About the only time you may need this is when
+# running another nameserver on the same machine.
+bind-interfaces
+
+# If this line is uncommented, dnsmasq will read /etc/ethers and act
+# on the ethernet-address/IP pairs found there just as if they had
+# been given as --dhcp-host options. Useful if you keep
+# MAC-address/host mappings there for other purposes.
+#read-ethers

+ 23 - 0
conf/dnsmasq_dhcpdv6.conf.tpl

@@ -0,0 +1,23 @@
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
+# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
+# so that clients can use SLAAC addresses as well as DHCP ones.
+dhcp-range=interface:<TPL:WIFI_DEVICE>,<TPL:IP6_NET>,slaac,64,4h
+
+# Send DHCPv6 option. Note [] around IPv6 addresses.
+dhcp-option=option6:dns-server,[<TPL:IP6_DNS0>],[<TPL:IP6_DNS1>]

BIN
conf/firmware_htc-7010.fw


BIN
conf/firmware_htc-9271.fw


+ 25 - 5
conf/hostapd.conf.tpl

@@ -1,14 +1,34 @@
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 interface=<TPL:WIFI_DEVICE>
 ssid=<TPL:WIFI_SSID>
+
 hw_mode=g
 <TPL:N_COMMENT>ieee80211n=1
 <TPL:N_COMMENT>wmm_enabled=1
+
 channel=<TPL:WIFI_CHANNEL>
 macaddr_acl=0
 auth_algs=1
 ignore_broadcast_ssid=0
-wpa=2
-wpa_passphrase=<TPL:WIFI_PASSPHRASE>
-wpa_key_mgmt=WPA-PSK
-wpa_pairwise=TKIP
-rsn_pairwise=CCMP
+
+<TPL:SEC_COMMENT>wpa=2
+<TPL:SEC_COMMENT>wpa_passphrase=<TPL:WIFI_PASSPHRASE>
+<TPL:SEC_COMMENT>wpa_key_mgmt=WPA-PSK
+<TPL:SEC_COMMENT>wpa_pairwise=TKIP
+<TPL:SEC_COMMENT>rsn_pairwise=CCMP

+ 164 - 147
conf/init_ynh-hotspot

@@ -9,6 +9,23 @@
 # Description:       Set prerequisites for wifi hotspot.
 ### END INIT INFO
 
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 # Functions
 ## State functions
 
@@ -20,11 +37,6 @@ has_ip6delegatedprefix() {
   [ "${ynh_ip6_net}" != none ]
 }
 
-is_ndproxy_set() {
-  proxy=$(ip -6 neighbour show proxy)
-  [ ! -z "${proxy}" ]
-}
-
 is_nat_set() {
   internet_device=${1}
 
@@ -46,30 +58,43 @@ is_forwarding_set() {
   [ "${ip6}" -eq 1 -a "${ip4}" -eq 1 ]
 }
 
+is_dhcpdv6_set() {
+  [ -e /etc/dnsmasq.d/dhcpdv6.conf ]
+}
+
+is_dhcpdv4_set() {
+  [ -e /etc/dnsmasq.d/dhcpdv4.conf ]
+}
+
 is_hostapd_running() {
   service hostapd status &> /dev/null
-}
 
-is_radvd_running() {
-  service radvd status &> /dev/null
+  if [ $? -eq 0 ]; then
+
+    # If the wifi antenna was unplugged
+    if ip link show dev "${ynh_wifi_device}" | grep -q DOWN; then
+      service hostapd stop &> /dev/null
+      return 1
+    fi
+
+    return 0
+  fi
+
+  return 1
 }
 
-is_dhcpd_running() {
-  service isc-dhcp-server status &> /dev/null
+is_dnsmasq_running() {
+  service dnsmasq status &> /dev/null
 }
 
 is_running() {
-  ( has_ip6delegatedprefix && is_ip6addr_set && is_radvd_running && is_ndproxy_set || ! has_ip6delegatedprefix )\
+  ( has_ip6delegatedprefix && is_ip6addr_set && is_dhcpdv6_set || ! has_ip6delegatedprefix )\
   && is_nat_set "${new_internet_device}" && is_ip4nataddr_set && is_forwarding_set && is_hostapd_running\
-  && is_dhcpd_running
+  && is_dhcpdv4_set && is_dnsmasq_running
 }
 
 ## Setters
 
-set_ndproxy() {
-  ip -6 neighbour add proxy "${ynh_ip6_addr}" dev "${ynh_wifi_device}"
-}
-
 set_nat() {
   internet_device=${1}
 
@@ -90,6 +115,24 @@ set_forwarding() {
   sysctl -w net.ipv4.conf.all.forwarding=1 > /dev/null
 }
 
+set_dhcpd() {
+  if has_ip6delegatedprefix; then
+    cp /etc/dnsmasq.d.tpl/dhcpdv6.conf.tpl /etc/dnsmasq.d/dhcpdv6.conf
+  
+    sed "s|<TPL:WIFI_DEVICE>|${ynh_wifi_device}|g" -i /etc/dnsmasq.d/dhcpdv6.conf
+    sed "s|<TPL:IP6_NET>|${ynh_ip6_net}|g" -i /etc/dnsmasq.d/dhcpdv6.conf
+    sed "s|<TPL:IP6_DNS0>|${ynh_ip6_dns0}|g" -i /etc/dnsmasq.d/dhcpdv6.conf
+    sed "s|<TPL:IP6_DNS1>|${ynh_ip6_dns1}|g" -i /etc/dnsmasq.d/dhcpdv6.conf
+  fi
+
+  cp /etc/dnsmasq.d.tpl/dhcpdv4.conf.tpl /etc/dnsmasq.d/dhcpdv4.conf
+
+  sed "s|<TPL:IP4_DNS0>|${ynh_ip4_dns0}|g" -i /etc/dnsmasq.d/dhcpdv4.conf
+  sed "s|<TPL:IP4_DNS1>|${ynh_ip4_dns1}|g" -i /etc/dnsmasq.d/dhcpdv4.conf
+  sed "s|<TPL:WIFI_DEVICE>|${ynh_wifi_device}|g" -i /etc/dnsmasq.d/dhcpdv4.conf
+  sed "s|<TPL:IP4_NAT_PREFIX>|${ynh_ip4_nat_prefix}|g" -i /etc/dnsmasq.d/dhcpdv4.conf
+}
+
 start_hostapd() {
   cp /etc/hostapd/hostapd.conf{.tpl,}
 
@@ -104,37 +147,17 @@ start_hostapd() {
     sed "s|<TPL:N_COMMENT>|#|g" -i /etc/hostapd/hostapd.conf
   fi
 
-  service hostapd start
-}
-
-start_radvd() {
-  cp /etc/radvd.conf{.tpl,}
-
-  sed "s|<TPL:WIFI_DEVICE>|${ynh_wifi_device}|g" -i /etc/radvd.conf
-  sed "s|<TPL:IP6_NET>|${ynh_ip6_net}|g" -i /etc/radvd.conf
-  sed "s|<TPL:IP6_DNS0>|${ynh_ip6_dns0}|g" -i /etc/radvd.conf
-  sed "s|<TPL:IP6_DNS1>|${ynh_ip6_dns1}|g" -i /etc/radvd.conf
-
-  service radvd start
-}
-
-start_dhcpd() {
-  cp /etc/dhcp/dhcpd.conf{.tpl,}
-
-  sed "s|<TPL:IP4_DNS0>|${ynh_ip4_dns0}|g" -i /etc/dhcp/dhcpd.conf
-  sed "s|<TPL:IP4_DNS1>|${ynh_ip4_dns1}|g" -i /etc/dhcp/dhcpd.conf
-  sed "s|<TPL:WIFI_DEVICE>|${ynh_wifi_device}|g" -i /etc/dhcp/dhcpd.conf
-  sed "s|<TPL:IP4_NAT_PREFIX>|${ynh_ip4_nat_prefix}|g" -i /etc/dhcp/dhcpd.conf
+  if [ "${ynh_wifi_secure}" -eq 1 ]; then
+    sed "s|<TPL:SEC_COMMENT>||g" -i /etc/hostapd/hostapd.conf
+  else
+    sed "s|<TPL:SEC_COMMENT>|#|g" -i /etc/hostapd/hostapd.conf
+  fi
 
-  service isc-dhcp-server start
+  service hostapd start
 }
 
 ## Unsetters
 
-unset_ndproxy() {
-  ip -6 neighbour delete proxy "${ynh_ip6_addr}" dev "${ynh_wifi_device}"
-}
-
 unset_nat() {
   internet_device=${1}
 
@@ -149,6 +172,10 @@ unset_ip6addr() {
   ip address delete "${ynh_ip6_addr}/64" dev "${ynh_wifi_device}"
 }
 
+unset_dhcpd() {
+  rm -f /etc/dnsmasq.d/dhcpdv?.conf
+}
+
 unset_forwarding() {
   sysctl -w net.ipv6.conf.all.forwarding=0 > /dev/null
   sysctl -w net.ipv4.conf.all.forwarding=0 > /dev/null
@@ -158,14 +185,6 @@ stop_hostapd() {
   service hostapd stop
 }
 
-stop_radvd() {
-  service radvd stop
-}
-
-stop_dhcpd() {
-  service isc-dhcp-server stop
-}
-
 ## Tools
 
 moulinette_get() {
@@ -206,55 +225,61 @@ moulinette_set() {
   fi
 }
 
-# Restart php5-fpm at the first start (it needs to be restarted after the slapd start)
-if [ ! -e /tmp/.ynh-hotspot-boot ]; then
-  touch /tmp/.ynh-hotspot-boot
-  service php5-fpm restart
-fi
-
-# Variables
-
-echo -n "Retrieving Yunohost settings... "
-
-ynh_wifi_device=$(moulinette_get wifi_device)
-ynh_wifi_ssid=$(moulinette_get wifi_ssid)
-ynh_wifi_passphrase=$(moulinette_get wifi_passphrase)
-ynh_wifi_channel=$(moulinette_get wifi_channel)
-ynh_wifi_n=$(moulinette_get wifi_n)
-ynh_ip6_addr=$(moulinette_get ip6_addr)
-ynh_ip6_net=$(moulinette_get ip6_net)
-ynh_ip6_dns0=$(moulinette_get ip6_dns0)
-ynh_ip6_dns1=$(moulinette_get ip6_dns1)
-ynh_ip4_dns0=$(moulinette_get ip4_dns0)
-ynh_ip4_dns1=$(moulinette_get ip4_dns1)
-ynh_ip4_nat_prefix=$(moulinette_get ip4_nat_prefix)
-
-old_internet_device=$(moulinette_get internet_device)
-new_internet_device=$(ip route | awk '/default via/ { print $NF; }')
-
-# Switch the NAT interface if there is a VPN
-ip link show dev tun0 &> /dev/null
-if [ "$?" -eq 0 ]; then
-  new_internet_device=tun0
-fi
-
-echo "OK"
-
-# Check IPv6 delegated prefix from vpnclient
-vpnclient_ip6_net=$(moulinette_vpnclient_get ip6_net)
+if [ "$1" != restart ]; then
 
-if [ ! -z "${vpnclient_ip6_addr}" ]; then
-  if [ "${ynh_ip6_net}" == none ]; then
-    ynh_ip6_net=$vpnclient_ip6_net
-    ynh_ip6_addr=$(moulinette_vpnclient_get ip6_addr)
+  # Restart php5-fpm at the first start (it needs to be restarted after the slapd start)
+  if [ ! -e /tmp/.ynh-hotspot-boot ]; then
+    touch /tmp/.ynh-hotspot-boot
+    service php5-fpm restart
+  fi
   
-    moulinette_set ip6_net "${ynh_ip6_net}"
-    moulinette_set ip6_addr "${ynh_ip6_addr}"
-  else
-    if [ "${ynh_ip6_net}" != "${vpnclient_ip6_net}" ]; then
-      echo "[WARN] The IPv6 delegated prefix is different from the vpnclient one"
+  # Variables
+  
+  echo -n "Retrieving Yunohost settings... "
+  
+  ynh_service_enabled=$(moulinette_get service_enabled)
+  ynh_wifi_device=$(moulinette_get wifi_device)
+  ynh_wifi_ssid=$(moulinette_get wifi_ssid)
+  ynh_wifi_secure=$(moulinette_get wifi_secure)
+  ynh_wifi_passphrase=$(moulinette_get wifi_passphrase)
+  ynh_wifi_channel=$(moulinette_get wifi_channel)
+  ynh_wifi_n=$(moulinette_get wifi_n)
+  ynh_ip6_addr=$(moulinette_get ip6_addr)
+  ynh_ip6_net=$(moulinette_get ip6_net)
+  ynh_ip6_dns0=$(moulinette_get ip6_dns0)
+  ynh_ip6_dns1=$(moulinette_get ip6_dns1)
+  ynh_ip4_dns0=$(moulinette_get ip4_dns0)
+  ynh_ip4_dns1=$(moulinette_get ip4_dns1)
+  ynh_ip4_nat_prefix=$(moulinette_get ip4_nat_prefix)
+  
+  old_internet_device=$(moulinette_get internet_device)
+  new_internet_device=$(ip route | awk '/default via/ { print $NF; }')
+  
+  # Switch the NAT interface if there is a VPN
+  ip link show dev tun0 &> /dev/null
+  if [ "$?" -eq 0 ]; then
+    new_internet_device=tun0
+  fi
+  
+  echo "OK"
+  
+  # Check IPv6 delegated prefix from vpnclient
+  vpnclient_ip6_net=$(moulinette_vpnclient_get ip6_net)
+  
+  if [ ! -z "${vpnclient_ip6_addr}" ]; then
+    if [ "${ynh_ip6_net}" == none ]; then
+      ynh_ip6_net=$vpnclient_ip6_net
+      ynh_ip6_addr=$(moulinette_vpnclient_get ip6_addr)
+    
+      moulinette_set ip6_net "${ynh_ip6_net}"
+      moulinette_set ip6_addr "${ynh_ip6_addr}"
+    else
+      if [ "${ynh_ip6_net}" != "${vpnclient_ip6_net}" ]; then
+        echo "[WARN] The IPv6 delegated prefix is different from the vpnclient one"
+      fi
     fi
   fi
+
 fi
 
 # Script
@@ -263,6 +288,8 @@ case "$1" in
   start)
     if is_running; then
       echo "Already started"
+    elif [ "${ynh_service_enabled}" -eq 0 ]; then
+      echo "Disabled service"
     else
       echo "[hotspot] Starting..."
       touch /tmp/.ynh-hotspot-started
@@ -273,12 +300,6 @@ case "$1" in
         moulinette_set vpnclient no
       fi
 
-      # Set NDP proxy
-      if has_ip6delegatedprefix && ! is_ndproxy_set; then
-        echo "Set NDP proxy"
-        set_ndproxy
-      fi
-
       # Check old state of the ipv4 NAT settings
       if [ ! -z "${old_internet_device}" -a "${new_internet_device}" != "${old_internet_device}" ]\
          && is_nat_set "${old_internet_device}"; then
@@ -314,22 +335,17 @@ case "$1" in
       if ! is_hostapd_running; then
         echo "Run hostapd"
         start_hostapd
-        sleep 1
       fi
 
-      # Run radvd
-      # must be running after hostapd
-      if has_ip6delegatedprefix && ! is_radvd_running; then
-        echo "Run radvd"
-        start_radvd
+      # Run DHCP servers
+      if ( has_ip6delegatedprefix && ! is_dhcpdv6_set ) || ! is_dhcpdv4_set; then
+        echo "Set DHCP servers (dnsmasq)"
+        set_dhcpd
       fi
 
-      # Run dhcpd
-      # "options routers" addr (is_ip6addr_set) must be set before
-      if ! is_dhcpd_running; then
-        echo "Run dhcpd"
-        start_dhcpd
-      fi
+      # Restart dhcpd
+      service bind9 stop &> /dev/null
+      service dnsmasq restart
 
       # Update dynamic settings
       moulinette_set internet_device "${new_internet_device}"
@@ -337,13 +353,8 @@ case "$1" in
   ;;
   stop)
     echo "[hotspot] Stopping..."
-    rm /tmp/.ynh-hotspot-started
+    rm -f /tmp/.ynh-hotspot-started
 
-    if has_ip6delegatedprefix && is_ndproxy_set; then
-      echo "Unset NDP proxy"
-      unset_ndproxy
-    fi
-  
     if is_nat_set "${old_internet_device}"; then
       echo "Unset NAT"
       unset_nat "${old_internet_device}"
@@ -364,58 +375,64 @@ case "$1" in
       unset_forwarding
     fi
   
+    if is_dhcpdv6_set || is_dhcpdv4_set; then
+      echo "Stop DHCP servers"
+      unset_dhcpd
+    fi
+
     if is_hostapd_running; then
       echo "Stop hostapd"
       stop_hostapd
     fi
-  
-    if has_ip6delegatedprefix && is_radvd_running; then
-      echo "Stop radvd"
-      stop_radvd
-    fi
-  
-    if is_dhcpd_running; then
-      echo "Stop dhcpd"
-      stop_dhcpd
-    fi
 
     if has_vpnclient_app; then
       service ynh-vpnclient start
     fi
+
+    service dnsmasq restart
+  ;;
+  restart)
+    $0 stop
+    $0 start
   ;;
   status)
     exitcode=0
 
+    if [ "${ynh_service_enabled}" -eq 0 ]; then
+      echo "[ERR] Hotspot Service disabled"
+      exitcode=1
+    fi
+
     echo "[INFO] Autodetected internet interface: ${new_internet_device} (last start: ${old_internet_device})"
 
     if has_ip6delegatedprefix; then
       echo "[INFO] IPv6 delegated prefix found"
       echo "[INFO] IPv6 address computed from the delegated prefix: ${ynh_ip6_addr}"
 
-      if is_ndproxy_set; then
-        echo "[OK] NDP proxy set"
-      else
-        echo "[ERR] No NDP proxy set"
-        exitcode=1
-      fi
-  
       if is_ip6addr_set; then
         echo "[OK] IPv6 address set"
       else
         echo "[ERR] No IPv6 address set"
         exitcode=1
       fi
-  
-      if is_radvd_running; then
-        echo "[OK] Radvd is running"
+
+      if is_dhcpdv6_set; then
+        echo "[OK] SLAAC & DHCPv6 server set"
       else
-        echo "[ERR] Radvd is not running"
+        echo "[ERR] No SLAAC & DHCPv6 server set"
         exitcode=1
       fi
     else
       echo "[INFO] No IPv6 delegated prefix found"
     fi
 
+    if is_dhcpdv4_set; then
+      echo "[OK] DHCPv4 server set"
+    else
+      echo "[ERR] No DHCPv4 server set"
+      exitcode=1
+    fi
+
     if is_nat_set "${new_internet_device}"; then
       echo "[OK] IPv4 NAT set"
     else
@@ -437,24 +454,24 @@ case "$1" in
       exitcode=1
     fi
 
-    if is_hostapd_running; then
-      echo "[OK] Hostapd is running"
+    if is_dnsmasq_running; then
+      echo "[OK] Dnsmasq is running"
     else
-      echo "[ERR] Hostapd is not running"
+      echo "[ERR] Dnsmasq is not running"
       exitcode=1
     fi
 
-    if is_dhcpd_running; then
-      echo "[OK] Dhcpd is running"
+    if is_hostapd_running; then
+      echo "[OK] Hostapd is running"
     else
-      echo "[ERR] Dhcpd is not running"
+      echo "[ERR] Hostapd is not running"
       exitcode=1
     fi
 
     exit ${exitcode}
   ;;
   *)
-    echo "Usage: $0 {start|stop|status}"
+    echo "Usage: $0 {start|stop|restart|status}"
     exit 1
   ;;
 esac

+ 17 - 0
conf/ipv6_compressed

@@ -1,3 +1,20 @@
 #!/bin/bash
 
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 sipcalc "${1}" | grep Compressed | awk '{ print $NF; }'

+ 17 - 0
conf/ipv6_expanded

@@ -1,3 +1,20 @@
 #!/bin/bash
 
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 sipcalc "${1}" | grep Expanded | awk '{ print $NF; }'

+ 38 - 17
conf/nginx_wifiadmin.conf

@@ -1,19 +1,40 @@
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 location <TPL:NGINX_LOCATION> {
-       alias <TPL:NGINX_REALPATH>;
-       if ($scheme = http) {
-           rewrite ^ https://$server_name$request_uri? permanent;
-       }
-       client_max_body_size 10G;
-       index index.php;
-       try_files $uri $uri/ index.php;
-       location ~ [^/]\.php(/|$) {
-           fastcgi_split_path_info ^(.+?\.php)(/.*)$;
-           fastcgi_pass unix:/var/run/php5-fpm-<TPL:PHP_NAME>.sock;
-           fastcgi_index index.php;
-           include fastcgi_params;
-           fastcgi_read_timeout 600;
-           fastcgi_param   REMOTE_USER   $remote_user;
-           fastcgi_param  PATH_INFO $fastcgi_path_info;
-       }
-       include conf.d/yunohost_panel.conf.inc;
+  alias <TPL:NGINX_REALPATH>;
+
+  if ($scheme = http) {
+    rewrite ^ https://$server_name$request_uri? permanent;
+  }
+
+  client_max_body_size 10G;
+  index index.php;
+  try_files $uri $uri/ index.php;
+
+  location ~ [^/]\.php(/|$) {
+    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+    fastcgi_pass unix:/var/run/php5-fpm-<TPL:PHP_NAME>.sock;
+    fastcgi_index index.php;
+    include fastcgi_params;
+    fastcgi_read_timeout 600;
+    fastcgi_param REMOTE_USER $remote_user;
+    fastcgi_param PATH_INFO $fastcgi_path_info;
+  }
+
+  include conf.d/yunohost_panel.conf.inc;
 }

+ 21 - 61
conf/phpfpm_wifiadmin.conf

@@ -1,21 +1,25 @@
-; Start a new pool named 'www'.
+; Wifi Hotspot app for YunoHost 
+; Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+; Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
+; Start a new pool named '<TPL:PHP_NAME>'.
 ; the variable $pool can we used in any directive and will be replaced by the
 ; pool name ('www' here)
 [<TPL:PHP_NAME>]
 
-; Per pool prefix
-; It only applies on the following directives:
-; - 'slowlog'
-; - 'listen' (unixsocket)
-; - 'chroot'
-; - 'chdir'
-; - 'php_values'
-; - 'php_admin_values'
-; When not set, the global prefix (or /usr) applies instead.
-; Note: This directive can also be relative to the global prefix.
-; Default Value: none
-;prefix = /path/to/pools/$pool
-
 ; The address on which to accept FastCGI requests.
 ; Valid syntaxes are:
 ;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on
@@ -26,18 +30,6 @@
 ; Note: This value is mandatory.
 listen = /var/run/php5-fpm-<TPL:PHP_NAME>.sock
 
-; Set listen(2) backlog. A value of '-1' means unlimited.
-; Default Value: 128 (-1 on FreeBSD and OpenBSD)
-;listen.backlog = -1
-
-; List of ipv4 addresses of FastCGI clients which are allowed to connect.
-; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
-; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
-; must be separated by a comma. If this value is left blank, connections will be
-; accepted from any ip address.
-; Default Value: any
-;listen.allowed_clients = 127.0.0.1
-
 ; Set permissions for unix socket, if one is used. In Linux, read/write
 ; permissions must be set in order to allow connections from a web server. Many
 ; BSD-derived systems allow connections regardless of permissions.
@@ -149,11 +141,6 @@ pm.status_path = /fpm-status
 ; Default Value: not set
 ping.path = /ping
 
-; This directive may be used to customize the response of a ping request. The
-; response is formatted as text/plain with a 200 response code.
-; Default Value: pong
-;ping.response = pong
-
 ; The timeout for serving a single request after which the worker process will
 ; be killed. This option should be used when the 'max_execution_time' ini option
 ; does not stop script execution for some reason. A value of '0' means 'off'.
@@ -181,17 +168,6 @@ rlimit_files = 4096
 ; Default Value: system defined value
 rlimit_core = 0
 
-; Chroot to this directory at the start. This value must be defined as an
-; absolute path. When this value is not set, chroot is not used.
-; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
-; of its subdirectories. If the pool prefix is not set, the global prefix
-; will be used instead.
-; Note: chrooting is a great security feature and should be used whenever
-;       possible. However, all PHP paths will be relative to the chroot
-;       (error_log, sessions.save_path, ...).
-; Default Value: not set
-;chroot =
-
 ; Chdir to this directory at the start.
 ; Note: relative path can be used.
 ; Default Value: current directory or / when chroot
@@ -204,15 +180,6 @@ chdir = <TPL:NGINX_REALPATH>
 ; Default Value: no
 catch_workers_output = no
 
-; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
-; the current environment.
-; Default Value: clean env
-;env[HOSTNAME] = $HOSTNAME
-;env[PATH] = /usr/local/bin:/usr/bin:/bin
-;env[TMP] = /tmp
-;env[TMPDIR] = /tmp
-;env[TEMP] = /tmp
-
 ; Additional php.ini defines, specific to this pool of workers. These settings
 ; overwrite the values previously defined in the php.ini. The directives are the
 ; same as the PHP SAPI:
@@ -221,22 +188,15 @@ catch_workers_output = no
 ;   php_admin_value/php_admin_flag - these directives won't be overwritten by
 ;                                     PHP call 'ini_set'
 ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
-
+;
 ; Defining 'extension' will load the corresponding shared extension from
 ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
 ; overwrite previously defined php.ini values, but will append the new value
 ; instead.
-
+;
 ; Note: path INI options can be relative and will be expanded with the prefix
 ; (pool, global or /usr)
 
-; Default Value: nothing is defined by default except the values in php.ini and
-;                specified at startup with the -d argument
-;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
-;php_flag[display_errors] = off
-;php_admin_value[error_log] = /var/log/fpm-php.www.log
-;php_admin_flag[log_errors] = on
-;php_admin_value[memory_limit] = 32M
-
+php_value[max_execution_time] = 600
 php_value[upload_max_filesize] = 10G
 php_value[post_max_size] = 10G

+ 0 - 6
conf/radvd.conf.tpl

@@ -1,6 +0,0 @@
-interface <TPL:WIFI_DEVICE>
-{
-  AdvSendAdvert on;
-  prefix <TPL:IP6_NET>/64 { };
-  RDNSS <TPL:IP6_DNS0> <TPL:IP6_DNS1> { };
-};

+ 9 - 0
manifest.json

@@ -47,6 +47,15 @@
             "fr": "Choisissez un mot de passe wifi (au minimum 8 caractères pour le WPA2)"
         },
         "example": "VhegT8oev0jZI"
+      },
+      {
+        "name": "firmware_nonfree",
+        "ask": {
+            "en": "Install non-free firmwares for the wifi dongle (yes/no)",
+            "fr": "Installer des firmwares non-libres pour la clé USB wifi (yes/no)"
+        },
+        "example": "yes",
+        "default": "yes"
       }
     ]
   }

+ 9 - 0
manifest.json.options

@@ -49,6 +49,15 @@
         "example": "VhegT8oev0jZI"
       },
       {
+        "name": "firmware_nonfree",
+        "ask": {
+            "en": "Install non-free firmwares for the wifi dongle (yes/no)",
+            "fr": "Installer des firmwares non-libres pour la clé USB wifi (yes/no)"
+        },
+        "example": "yes",
+        "default": "yes"
+      },
+      {
         "name": "ip6_net",
         "ask": {
             "en": "Select your IPv6 delegated prefix (leave empty if your Internet Service Provider does not give you a delegated prefix, but you will not have IPv6)",

BIN
screenshot.png


+ 58 - 15
scripts/install

@@ -1,17 +1,35 @@
 #!/bin/bash
 
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 # Retrieve arguments
 domain=${1}
 url_path=${2}
 wifi_ssid=${3}
 wifi_passphrase=${4}
+firmware_nonfree=${5}
 
 ##
 ## These arguments are optional but YunoHost is not yet able to handle them with the web installer
 ## See manifest.json.options
 ##
 #
-#ip6_net=${5}
+#ip6_net=${6}
 
 # Check arguments
 if [ -z "${wifi_ssid}" -o -z "${wifi_passphrase}" ]; then
@@ -38,9 +56,17 @@ if [ ! $? -eq 0 ]; then
 fi
 
 # Install packages
-# TODO: Replace isc-dhcp-server by dnsmasq (currently negotiating with the YunoHost team to
-# also replace bind9 by dnsmasq)
-packages='php5-fpm sipcalc hostapd radvd isc-dhcp-server iptables wireless-tools wireless-tools'
+packages='php5-fpm sipcalc hostapd iptables wireless-tools dnsmasq'
+export DEBIAN_FRONTEND=noninteractive
+
+# Packaged USB Wireless Device firmwares
+# Based on https://wiki.debian.org/WiFi#USB_Devices
+if [ "${firmware_nonfree}" == yes ]; then
+  packages="$packages firmware-atheros atmel-firmware firmware-linux-free firmware-linux-nonfree firmware-realtek firmware-ralink firmware-libertas zd1211-firmware"
+else
+  packages="$packages firmware-linux-free"
+fi
+
 sudo apt-get --assume-yes --force-yes install ${packages}
 
 if [ $? -ne 0 ]; then
@@ -52,6 +78,16 @@ fi
 if [ -z "${ip6_net}" ]; then
   ip6_net=none
   ip6_addr=none
+
+  if [ -e /tmp/.ynh-vpnclient-started ]; then
+    vpnclient_ip6_net=$(sudo yunohost app setting vpnclient ip6_net 2>&1)
+    vpnclient_ip6_addr=$(sudo yunohost app setting vpnclient ip6_addr 2>&1)
+
+    if [[ "${vpnclient_ip6_net}" =~ :: && "${vpnclient_ip6_addr}" =~ :: ]]; then
+      ip6_net=${vpnclient_ip6_net}
+      ip6_addr=${vpnclient_ip6_addr}
+    fi
+  fi
 #else
 #  ip6_net=$(bash ../conf/ipv6_expanded "${ip6_net}")
 #
@@ -79,7 +115,9 @@ if [ $? -eq 0 ]; then
 fi
 
 # Save arguments
+sudo yunohost app setting hotspot service_enabled -v 1
 sudo yunohost app setting hotspot wifi_ssid -v "${wifi_ssid}"
+sudo yunohost app setting hotspot wifi_secure -v 1
 sudo yunohost app setting hotspot wifi_passphrase -v "${wifi_passphrase}"
 sudo yunohost app setting hotspot wifi_device -v "${wifi_device}"
 sudo yunohost app setting hotspot wifi_channel -v 6
@@ -98,12 +136,22 @@ sudo install -o root -g root -m 0755 ../conf/ipv6_expanded /usr/local/bin/
 sudo install -o root -g root -m 0755 ../conf/ipv6_compressed /usr/local/bin/
 
 # Copy confs
+sudo mkdir -pm 0755 /var/log/nginx/
+sudo mkdir -pm 0755 /etc/dnsmasq.d.tpl/
+sudo chown root: /etc/dnsmasq.d.tpl/
+
 sudo install -b -o root -g root -m 0644 ../conf/hostapd.conf.tpl /etc/hostapd/
-sudo install -b -o root -g root -m 0644 ../conf/radvd.conf.tpl /etc/
-sudo install -b -o root -g root -m 0644 ../conf/dhcpd.conf.tpl /etc/dhcp/
+sudo install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv6.conf.tpl /etc/dnsmasq.d.tpl/dhcpdv6.conf.tpl
+sudo install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv4.conf.tpl /etc/dnsmasq.d.tpl/dhcpdv4.conf.tpl
 sudo install -b -o root -g root -m 0644 ../conf/nginx_wifiadmin.conf "/etc/nginx/conf.d/${domain}.d/wifiadmin.conf"
 sudo install -b -o root -g root -m 0644 ../conf/phpfpm_wifiadmin.conf /etc/php5/fpm/pool.d/wifiadmin.conf
 
+# Copy (free) firmwares
+# Extract from http://packages.trisquel.info/toutatis-updates/open-ath9k-htc-firmware
+# https://www.fsf.org/news/ryf-certification-thinkpenguin-usb-with-atheros-chip
+sudo install -b -o root -g root -m 0644 ../conf/firmware_htc-7010.fw /lib/firmware/htc-7010.fw
+sudo install -b -o root -g root -m 0644 ../conf/firmware_htc-9271.fw /lib/firmware/htc-9271.fw
+
 # Copy web sources
 sudo mkdir -pm 0755 /var/www/wifiadmin/
 sudo cp -a ../sources/* /var/www/wifiadmin/
@@ -126,7 +174,6 @@ sudo sed 's|<TPL:PHP_NAME>|wifiadmin|g' -i /etc/php5/fpm/pool.d/wifiadmin.conf
 sudo sed 's|<TPL:PHP_USER>|admin|g' -i /etc/php5/fpm/pool.d/wifiadmin.conf
 sudo sed 's|<TPL:PHP_GROUP>|admins|g' -i /etc/php5/fpm/pool.d/wifiadmin.conf
 sudo sed 's|<TPL:NGINX_REALPATH>|/var/www/wifiadmin/|g' -i /etc/php5/fpm/pool.d/wifiadmin.conf
-sudo sed 's|^;\?\s*max_execution_time.\+|max_execution_time = 600|' -i /etc/php5/fpm/php.ini
 
 # Fix sources
 sudo sed "s|<TPL:NGINX_LOCATION>|${url_path}|g" -i /var/www/wifiadmin/config.php
@@ -134,18 +181,14 @@ sudo sed "s|<TPL:NGINX_LOCATION>|${url_path}|g" -i /var/www/wifiadmin/config.php
 # Copy init script
 sudo install -o root -g root -m 0755 ../conf/init_ynh-hotspot /etc/init.d/ynh-hotspot
 
+# Update firewall for DHCP
+sudo yunohost firewall allow --no-upnp --ipv6 UDP 547
+sudo yunohost firewall allow --no-upnp UDP 67
+
 # Set default inits
 # The boot order of these services are important, so they are disabled by default
 # and the ynh-hotspot service handles them.
 # All services are registred by yunohost in order to prevent conflicts after the uninstall.
-sudo yunohost service add isc-dhcp-server
-sudo yunohost service stop isc-dhcp-server
-sudo yunohost service disable isc-dhcp-server
-
-sudo yunohost service add radvd
-sudo yunohost service stop radvd
-sudo yunohost service disable radvd
-
 sudo yunohost service add hostapd 
 sudo yunohost service stop hostapd 
 sudo yunohost service disable hostapd 

+ 28 - 1
scripts/remove

@@ -1,5 +1,22 @@
 #!/bin/bash
 
+# Wifi Hotspot app for YunoHost 
+# Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+# Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+
 # Retrieve arguments
 domain=$(sudo yunohost app setting hotspot domain)
 
@@ -9,11 +26,20 @@ sudo yunohost service remove ynh-hotspot
 sudo rm -f /etc/init.d/ynh-hotspot
 sudo rm -f /tmp/.ynh-hotspot-*
 
+# Update firewall for DHCP
+sudo yunohost firewall disallow --ipv6 UDP 547
+sudo yunohost firewall disallow UDP 67
+
 # Remove confs
+sudo rm -fr /etc/dnsmasq.d.tpl/
 sudo rm -f /etc/hostapd/hostapd.conf{.tpl,} /etc/radvd.conf{.tpl,} /etc/dhcp/dhcpd.conf{.tpl,}
 sudo rm -f /etc/nginx/conf.d/${domain}.d/wifiadmin.conf
 sudo rm -f /etc/php5/fpm/pool.d/wifiadmin.conf
 
+# Remove firmwares
+sudo rm -f /lib/firmware/htc-7010.fw
+sudo rm -f /lib/firmware/htc-9271.fw
+
 # Restart services
 sudo yunohost service stop php5-fpm
 sudo yunohost service start php5-fpm
@@ -24,6 +50,7 @@ sudo rm -rf /var/www/wifiadmin/
 
 # Remove packets
 # The yunohost policy is currently to not uninstall packets (dependency problems)
-## sudo apt-get --assume-yes --force-yes remove hostapd radvd isc-dhcp-server iptables sipcalc wireless-tools
+## sudo apt-get --assume-yes --force-yes remove hostapd iptables sipcalc wireless-tools
+## sudo apt-get --assume-yes --force-yes remove firmware-atheros atmel-firmware firmware-linux-free firmware-linux-nonfree firmware-realtek firmware-ralink firmware-libertas zd1211-firmware
 
 exit 0

+ 18 - 0
sources/config.php

@@ -1,5 +1,23 @@
 <?php
 
+/* Wifi Hotspot app for YunoHost 
+ * Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+ * Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+ */
+
 // Limonade configuration
 function configure() {
     option('env', ENV_PRODUCTION);

+ 126 - 73
sources/controller.php

@@ -1,5 +1,23 @@
 <?php
 
+/* Wifi Hotspot app for YunoHost 
+ * Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+ * Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+ */
+
 function moulinette_get($var) {
   return htmlspecialchars(exec('sudo yunohost app setting hotspot '.escapeshellarg($var)));
 }
@@ -42,6 +60,14 @@ function ipv6_compressed($ip) {
   return $output[0];
 }
 
+function is_connected_through_hotspot($ip6_net, $ip4_nat_prefix) {
+  $ip = $_SERVER['REMOTE_ADDR'];
+  $ip6_regex = '/^'.preg_quote(preg_replace('/::$/', '', $ip6_net)).':/';
+  $ip4_regex = '/^'.preg_quote($ip4_nat_prefix).'\./';
+
+  return (preg_match($ip6_regex, $ip) || preg_match($ip4_regex, $ip));
+}
+
 dispatch('/', function() {
   exec('sudo iwconfig', $devs);
   $wifi_device = moulinette_get('wifi_device');
@@ -59,8 +85,11 @@ dispatch('/', function() {
 
   $ip6_net = moulinette_get('ip6_net');
   $ip6_net = ($ip6_net == 'none') ? '' : $ip6_net;
+  $ip4_nat_prefix = moulinette_get('ip4_nat_prefix');
 
+  set('service_enabled', moulinette_get('service_enabled'));
   set('wifi_ssid', moulinette_get('wifi_ssid'));
+  set('wifi_secure', moulinette_get('wifi_secure'));
   set('wifi_passphrase', moulinette_get('wifi_passphrase'));
   set('wifi_channel', moulinette_get('wifi_channel'));
   set('wifi_n', moulinette_get('wifi_n'));
@@ -69,10 +98,11 @@ dispatch('/', function() {
   set('ip6_net', $ip6_net);
   set('ip6_dns0', moulinette_get('ip6_dns0'));
   set('ip6_dns1', moulinette_get('ip6_dns1'));
-  set('ip4_nat_prefix', moulinette_get('ip4_nat_prefix'));
+  set('ip4_nat_prefix', $ip4_nat_prefix);
   set('ip4_dns0', moulinette_get('ip4_dns0'));
   set('ip4_dns1', moulinette_get('ip4_dns1'));
   set('faststatus', service_faststatus() == 0);
+  set('is_connected_through_hotspot', is_connected_through_hotspot($ip6_net, $ip4_nat_prefix));
 
   return render('settings.html.php');
 });
@@ -83,95 +113,118 @@ dispatch_put('/settings', function() {
 
   $ip6_net = empty($_POST['ip6_net']) ? 'none' : $_POST['ip6_net'];
   $ip6_addr = 'none';
-
-  try {
-    if(empty($_POST['wifi_ssid']) || empty($_POST['wifi_passphrase']) || empty($_POST['wifi_channel'])) {
-      throw new Exception(T_('Your Wifi Hotspot needs a name, a password and a channel'));
-    }
-
-    if(strlen($_POST['wifi_passphrase']) < 8 || strlen($_POST['wifi_passphrase']) > 63) {
-      throw new Exception(T_('Your password must from 8 to 63 characters (WPA2 passphrase)'));
-    }
-
-    if(preg_match('/[^[:print:]]/', $_POST['wifi_passphrase'])) {
-      throw new Exception(T_('Only printable ASCII characters are permitted in your password'));
-    }
-
-    if(!$wifi_device_exists) {
-      throw new Exception(T_('The wifi antenna interface seems not exist on the system'));
-    }
-
-    if($ip6_net != 'none') {
-      $ip6_net = ipv6_expanded($ip6_net);
+  $ip6_dns0 = $_POST['ip6_dns0'];
+  $ip6_dns1 = $_POST['ip6_dns1'];
+  $service_enabled = isset($_POST['service_enabled']) ? 1 : 0;
+  $wifi_secure = isset($_POST['wifi_secure']) ? 1 : 0;
+
+  if($service_enabled == 1) {
+    try {
+      if(empty($_POST['wifi_ssid']) || empty($_POST['wifi_passphrase']) || empty($_POST['wifi_channel'])) {
+        throw new Exception(T_('Your Wifi Hotspot needs a name, a password and a channel'));
+      }
   
-      if(empty($ip6_net)) {
-        throw new Exception(T_('The IPv6 Delegated Prefix format looks bad'));
+      if(strlen($_POST['wifi_passphrase']) < 8 || strlen($_POST['wifi_passphrase']) > 63) {
+        throw new Exception(T_('Your password must from 8 to 63 characters (WPA2 passphrase)'));
       }
   
-      $ip6_blocs = explode(':', $ip6_net);
-      $ip6_addr = "${ip6_blocs[0]}:${ip6_blocs[1]}:${ip6_blocs[2]}:${ip6_blocs[3]}:${ip6_blocs[4]}:${ip6_blocs[5]}:${ip6_blocs[6]}:42";
+      if(preg_match('/[^[:print:]]/', $_POST['wifi_passphrase'])) {
+        throw new Exception(T_('Only printable ASCII characters are permitted in your password'));
+      }
   
-      $ip6_net = ipv6_compressed($ip6_net);
-      $ip6_addr = ipv6_compressed($ip6_addr);
-    }
-
-    $ip6_dns0 = ipv6_expanded($ip6_dns0);
+      if(!$wifi_device_exists) {
+        throw new Exception(T_('The wifi antenna interface seems not exist on the system'));
+      }
+  
+      if($ip6_net != 'none') {
+        $ip6_net = ipv6_expanded($ip6_net);
+    
+        if(empty($ip6_net)) {
+          throw new Exception(T_('The IPv6 Delegated Prefix format looks bad'));
+        }
+    
+        $ip6_blocs = explode(':', $ip6_net);
+        $ip6_addr = "${ip6_blocs[0]}:${ip6_blocs[1]}:${ip6_blocs[2]}:${ip6_blocs[3]}:${ip6_blocs[4]}:${ip6_blocs[5]}:${ip6_blocs[6]}:42";
+    
+        $ip6_net = ipv6_compressed($ip6_net);
+        $ip6_addr = ipv6_compressed($ip6_addr);
+      }
+  
+      if(!empty($ip6_dns0)) {
+        $ip6_dns0 = ipv6_expanded($ip6_dns0);
+  
+        if(empty($ip6_dns0)) {
+          throw new Exception(T_('The format of the first IPv6 DNS Resolver looks bad'));
+        }
 
-    if(empty($_POST['ip6_dns0'])) {
-      throw new Exception(T_('The format of the first IPv6 DNS Resolver looks bad'));
-    }
+        $ip6_dns0 = ipv6_compressed($ip6_dns0);
 
-    $ip6_dns0 = ipv6_compressed($ip6_dns0);
-    $ip6_dns1 = ipv6_expanded($ip6_dns1);
+        if(!empty($ip6_dns1)) {
+          $ip6_dns1 = ipv6_expanded($ip6_dns1);
+    
+          if(empty($ip6_dns1)) {
+             throw new Exception(T_('The format of the second IPv6 DNS Resolver looks bad'));
+          }
 
-    if(empty($_POST['ip6_dns1'])) {
-      throw new Exception(T_('The format of the second IPv6 DNS Resolver looks bad'));
+          $ip6_dns1 = ipv6_compressed($ip6_dns1);
+        }
+      }
+  
+      if(inet_pton($_POST['ip4_dns0']) === false) {
+        throw new Exception(T_('The format of the first IPv4 DNS Resolver looks bad'));
+      }
+  
+      if(inet_pton($_POST['ip4_dns1']) === false) {
+        throw new Exception(T_('The format of the second IPv4 DNS Resolver looks bad'));
+      }
+  
+      if(inet_pton("${_POST['ip4_nat_prefix']}.0") === false) {
+        throw new Exception(T_('The format of the IPv4 NAT Prefix (/24) looks bad : x.x.x expected)'));
+      }
+  
+      if(filter_var("${_POST['ip4_nat_prefix']}.0", FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) !== false) {
+        throw new Exception(T_('The IPv4 NAT Prefix must be from a private range'));
+      }
+  
+    } catch(Exception $e) {
+      flash('error', $e->getMessage().' ('.T_('configuration not updated').').');
+      goto redirect;
     }
+  }
 
-    $ip6_dns1 = ipv6_compressed($ip6_dns1);
+  stop_service();
 
-    if(inet_pton($_POST['ip4_dns0']) === false) {
-      throw new Exception(T_('The format of the first IPv4 DNS Resolver looks bad'));
-    }
+  moulinette_set('service_enabled', $service_enabled);
 
-    if(inet_pton($_POST['ip4_dns1']) === false) {
-      throw new Exception(T_('The format of the second IPv4 DNS Resolver looks bad'));
-    }
+  if($service_enabled == 1) {
+    moulinette_set('wifi_ssid', $_POST['wifi_ssid']);
+    moulinette_set('wifi_secure', $wifi_secure);
 
-    if(inet_pton("${_POST['ip4_nat_prefix']}.0") === false) {
-      throw new Exception(T_('The format of the IPv4 NAT Prefix (/24) looks bad : x.x.x expected)'));
+    if($wifi_secure == 1) {
+      moulinette_set('wifi_passphrase', $_POST['wifi_passphrase']);
     }
 
-    if(filter_var("${_POST['ip4_nat_prefix']}.0", FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) !== false) {
-      throw new Exception(T_('The IPv4 NAT Prefix must be from a private range'));
+    moulinette_set('wifi_channel', $_POST['wifi_channel']);
+    moulinette_set('wifi_n', isset($_POST['wifi_n']) ? 1 : 0);
+    moulinette_set('wifi_device', $_POST['wifi_device']);
+    moulinette_set('ip6_net', $ip6_net);
+    moulinette_set('ip6_addr', $ip6_addr);
+    moulinette_set('ip6_dns0', $_POST['ip6_dns0']);
+    moulinette_set('ip6_dns1', $_POST['ip6_dns1']);
+    moulinette_set('ip4_nat_prefix', $_POST['ip4_nat_prefix']);
+    moulinette_set('ip4_dns0', $_POST['ip4_dns0']);
+    moulinette_set('ip4_dns1', $_POST['ip4_dns1']);
+
+    $retcode = start_service();
+
+    if($retcode == 0) {
+      flash('success', T_('Configuration updated and service successfully reloaded'));
+    } else {
+      flash('error', T_('Configuration updated but service reload failed'));
     }
 
-  } catch(Exception $e) {
-    flash('error', $e->getMessage().' ('.T_('configuration not updated').').');
-    goto redirect;
-  }
-
-  stop_service();
-
-  moulinette_set('wifi_ssid', $_POST['wifi_ssid']);
-  moulinette_set('wifi_passphrase', $_POST['wifi_passphrase']);
-  moulinette_set('wifi_channel', $_POST['wifi_channel']);
-  moulinette_set('wifi_n', isset($_POST['wifi_n']) ? 1 : 0);
-  moulinette_set('wifi_device', $_POST['wifi_device']);
-  moulinette_set('ip6_net', $ip6_net);
-  moulinette_set('ip6_addr', $ip6_addr);
-  moulinette_set('ip6_dns0', $_POST['ip6_dns0']);
-  moulinette_set('ip6_dns1', $_POST['ip6_dns1']);
-  moulinette_set('ip4_nat_prefix', $_POST['ip4_nat_prefix']);
-  moulinette_set('ip4_dns0', $_POST['ip4_dns0']);
-  moulinette_set('ip4_dns1', $_POST['ip4_dns1']);
-
-  $retcode = start_service();
-
-  if($retcode == 0) {
-    flash('success', T_('Configuration updated and service successfully reloaded'));
   } else {
-    flash('error', T_('Configuration updated but service reload failed'));
+      flash('success', T_('Service successfully disabled'));
   }
 
   redirect:

+ 18 - 2
sources/index.php

@@ -1,11 +1,27 @@
 <?php
 
+/* Wifi Hotspot app for YunoHost 
+ * Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+ * Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+ */
+
 require dirname(__FILE__).'/lib/limonade.php';
 require dirname(__FILE__).'/controller.php';
-
 require dirname(__FILE__).'/lib/unix_func.php';
 //require '/usr/share/php/php-gettext/gettext.inc';
-
 require dirname(__FILE__).'/config.php';
 
 run();

+ 97 - 0
sources/public/css/style.css

@@ -1,3 +1,21 @@
+/* Wifi Hotspot app for YunoHost 
+ * Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+ * Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+ */
+
 li.status-info {
   color: #5BC0DE;
 }
@@ -43,3 +61,82 @@ div#github {
 div#github a {
   margin-left: 17px;
 }
+
+div#saveconfirmation {
+  display: none;
+  padding-right: 15px;
+  width: 60%;
+  margin: 0 auto;
+}
+
+div#saveconfirmation div#confirm {
+  background-color: #fff;
+  padding: 10px;
+  margin: 15px 0 0 0;
+  border: 1px solid #F5E79E;
+}
+
+div#wifiparty_screen {
+  top: 0;
+  left: 0;
+  display: none;
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  z-index: 998;
+  background-color: #fff;
+  text-align: center;
+}
+
+div#wifiparty_screen div.btn-group {
+  display: block;
+  margin: 5px;
+  opacity: 0.3;
+}
+
+div#wifiparty_screen div.btn-group:hover {
+  opacity: 0.7;
+}
+
+div#wifiparty_ssid_part {
+  background: #5CB85C;
+  color: #fff;
+}
+
+div#wifiparty_ssid_part div.btn-group {
+  float: left;
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 999;
+  opacity: 0.2;
+}
+
+div#wifiparty_ssid_part div.btn-group:hover {
+  opacity: 0.8;
+}
+
+span#wifiparty_ssid {
+  font-size: 70px;
+}
+
+div#wifiparty_passphrase {
+  clear: both;
+  font-size: 140px;
+  font-style: italic;
+  margin: 50px 20px;
+  word-wrap: break-word;
+  line-height: 0.9;
+}
+
+div#wifiparty_passphrase span.passdigit {
+  color: #428BCA;
+}
+
+div#wifiparty_passphrase span.passother {
+  color: #D9534F;
+}
+
+div#wifiparty_passphrase span.passspace {
+  color: #CCC;
+}

+ 69 - 0
sources/public/js/custom.js

@@ -1,3 +1,21 @@
+/* Wifi Hotspot app for YunoHost 
+ * Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+ * Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+ */
+
 $(document).ready(function() {
   $('.btn-group').button();
   $('[data-toggle="tooltip"]').tooltip();
@@ -36,6 +54,11 @@ $(document).ready(function() {
     $('#form').submit();
   });
 
+  $('#saveconfirm').click(function() {
+    $(this).hide();
+    $('#saveconfirmation').show();
+  });
+
   $('#status .close').click(function() {
     $(this).parent().hide();
   });
@@ -54,4 +77,50 @@ $(document).ready(function() {
       });
     }
   });
+
+  $('#wifiparty').click(function() {
+    $('#wifiparty_screen').show('slow');
+  });
+
+  $('#wifiparty_zoomin_ssid').mousedown(function() {
+    $('#wifiparty_ssid').css('fontSize', (parseInt($('#wifiparty_ssid').css('fontSize')) + 5) + "px");
+  });
+
+  $('#wifiparty_zoomout_ssid').mousedown(function() {
+    $('#wifiparty_ssid').css('fontSize', (parseInt($('#wifiparty_ssid').css('fontSize')) - 5) + "px");
+  });
+
+  $('#wifiparty_zoomin_passphrase').mousedown(function() {
+    $('#wifiparty_passphrase').css('fontSize', (parseInt($('#wifiparty_passphrase').css('fontSize')) + 7) + "px");
+  });
+
+  $('#wifiparty_zoomout_passphrase').mousedown(function() {
+    $('#wifiparty_passphrase').css('fontSize', (parseInt($('#wifiparty_passphrase').css('fontSize')) - 7) + "px");
+  });
+
+  $('#wifiparty_close').click(function() {
+    $('#wifiparty_screen').hide();
+  });
+
+  $('#wifi_secure').change(function() {
+    if($('#wifi_secure').parent().hasClass('off')) {
+      $('.secure').hide('slow');
+    } else {
+      $('.secure').show('slow');
+    }
+  });
+
+  $('#service_enabled').change(function() {
+    if($('#service_enabled').parent().hasClass('off')) {
+      $('.enabled').hide('slow');
+    } else {
+      $('.enabled').show('slow');
+    }
+  });
+});
+
+$(document).keydown(function(e) {
+  if(e.keyCode == 27) {
+    $('#wifiparty_close').click();
+  }
 });

+ 27 - 2
sources/views/layout.html.php

@@ -1,22 +1,46 @@
 <!doctype html>
+
+<!--
+  Wifi Hotspot app for YunoHost 
+  Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+  Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+-->
+
 <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
 <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
 <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
 <!--[if gt IE 8]><!--> <html class="no-js" lang="<?= $locale ?>"> <!--<![endif]-->
 <head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
   <title>Wifi Hotspot <? echo (isset($title)) ? "| ".$title : "" ?></title>
+
+  <meta charset="utf-8">
   <meta name="viewport" content="width=device-width">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+
   <link media="all" type="text/css" href="<?= PUBLIC_DIR ?>/bootstrap/css/bootstrap.min.css" rel="stylesheet">
   <link media="all" type="text/css" href="<?= PUBLIC_DIR ?>/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet">
   <link media="all" type="text/css" href="<?= PUBLIC_DIR ?>/css/bootstrap-toggle.min.css" rel="stylesheet">
   <link media="all" type="text/css" href="<?= PUBLIC_DIR ?>/css/style.css" rel="stylesheet">
+
   <script src="<?= PUBLIC_DIR ?>/jquery/jquery-2.1.1.min.js"></script>
   <script src="<?= PUBLIC_DIR ?>/bootstrap/js/bootstrap.min.js"></script>
   <script src="<?= PUBLIC_DIR ?>/js/bootstrap-toggle.min.js"></script>
   <script src="<?= PUBLIC_DIR ?>/js/custom.js"></script>
 </head>
+
 <body>
   <div class="container">
     <? if(isset($flash['error'])): ?>
@@ -42,4 +66,5 @@
     <div id="github"><a href="https://github.com/jvaubourg/hotspot_ynh"><?= T_('Any problem? Contribute!') ?></a> - AGPL 3.0</div>
   </div>
 </body>
+
 </html>

+ 88 - 6
sources/views/settings.html.php

@@ -1,3 +1,47 @@
+<!--
+  Wifi Hotspot app for YunoHost 
+  Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
+  Contribute at https://github.com/jvaubourg/hotspot_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 <http://www.gnu.org/licenses/>.
+-->
+
+<div id="wifiparty_screen">
+<div id="wifiparty_ssid_part">
+  <div class="btn-group" role="group">
+    <button type="button" class="btn btn-default" id="wifiparty_close"><span class="glyphicon glyphicon-eye-close"></span></button>
+    <button type="button" class="btn btn-default" id="wifiparty_zoomin_ssid"><span class="glyphicon glyphicon-zoom-in"></span></button>
+    <button type="button" class="btn btn-default" id="wifiparty_zoomout_ssid"><span class="glyphicon glyphicon-zoom-out"></span></button>
+  </div>
+
+  <span id="wifiparty_ssid"><span class="glyphicon glyphicon-signal"></span> <?= $wifi_ssid ?></span>
+</div>
+
+<div class="btn-group" role="group">
+  <button type="button" class="btn btn-default" id="wifiparty_zoomin_passphrase"><span class="glyphicon glyphicon-zoom-in"></span></button>
+  <button type="button" class="btn btn-default" id="wifiparty_zoomout_passphrase"><span class="glyphicon glyphicon-zoom-out"></span></button>
+</div>
+
+<div id="wifiparty_passphrase"><?php
+  $pw = preg_replace('/[^0-9a-z ]/i', '<span-class="passother">$0</span>', $wifi_passphrase);
+  $pw = preg_replace('/\d/', '<span-class="passdigit">$0</span>', $pw);
+  $pw = preg_replace('/ /', '<span class="passspace">&#x25AE;</span>', $pw);
+  $pw = preg_replace('/span-class/', 'span class', $pw);
+  echo $pw;
+?></div>
+</div>
+
 <h2><?= T_("Wifi Hotspot Configuration") ?></h2>
 <?php if($faststatus): ?>
   <span class="label label-success" data-toggle="tooltip" data-title="<?= T_('This is a fast status. Click on More details to show the complete status.') ?>"><?= T_('Running') ?></span>
@@ -21,6 +65,23 @@
 
       <div class="panel panel-default">
         <div class="panel-heading">
+          <h3 class="panel-title"><?= T_("Service") ?></h3>
+        </div>
+
+        <div style="padding: 14px 14px 0 10px">
+          <div class="form-group">
+            <label for="wifi_secure" class="col-sm-3 control-label"><?= T_('Hotspot Enabled') ?></label>
+            <div class="col-sm-9 input-group-btn">
+              <div class="input-group">
+                <input type="checkbox" class="form-control switch" name="service_enabled" id="service_enabled" value="1" <?= $service_enabled == 1 ? 'checked="checked"' : '' ?> />
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="panel panel-default enabled" <?= $service_enabled == 0 ? 'style="display: none"' : '' ?>>
+        <div class="panel-heading">
           <h3 class="panel-title"><?= T_("Wifi") ?></h3>
         </div>
 
@@ -31,11 +92,21 @@
               <input type="text" class="form-control" name="wifi_ssid" id="wifi_ssid" placeholder="myNeutralNetwork" value="<?= $wifi_ssid ?>" />
             </div>
           </div>
-  
+
           <div class="form-group">
+            <label for="wifi_secure" class="col-sm-3 control-label"><?= T_('Secure') ?></label>
+            <div class="col-sm-9 input-group-btn" data-toggle="tooltip" data-title="<?= T_('Disabling the Secure Wifi allows everyone to join the hotspot and spy the traffic (but it\'s perfect for a PirateBox)') ?>">
+              <div class="input-group">
+                <input type="checkbox" class="form-control switch" name="wifi_secure" id="wifi_secure" value="1" <?= $wifi_secure == 1 ? 'checked="checked"' : '' ?> />
+              </div>
+            </div>
+          </div>
+  
+          <div class="form-group secure" <?= $wifi_secure == 0 ? 'style="display: none"' : '' ?>>
             <label for="wifi_passphrase" class="col-sm-3 control-label"><?= T_('Password (WPA2)') ?></label>
-            <div class="col-sm-9">
+            <div class="input-group col-sm-9" style="padding: 0 15px">
               <input type="text" data-toggle="tooltip" data-title="<?= T_('At least 8 characters') ?>" class="form-control" name="wifi_passphrase" id="wifi_passphrase" placeholder="VhegT8oev0jZI" value="<?= $wifi_passphrase ?>" />
+              <a class="btn input-group-addon" id="wifiparty" data-toggle="tooltip" data-title="<?= T_('Show to your friends how to access to your hotspot') ?>"><span class="glyphicon glyphicon-fullscreen"></span></a>
             </div>
           </div>
   
@@ -62,8 +133,8 @@
             </div>
           </div>
 
-          <div class="form-group">
-            <label for="wifi_passphrase" class="col-sm-3 control-label"><?= T_('Wifi N') ?></label>
+          <div class="form-group" style="display: none">
+            <label for="wifi_n" class="col-sm-3 control-label"><?= T_('Wifi N') ?></label>
             <div class="col-sm-9 input-group-btn" data-toggle="tooltip" data-title="<?= T_('Only if your antenna is 802.11n compliant') ?>">
               <div class="input-group">
                 <input type="checkbox" class="form-control switch" name="wifi_n" id="wifi_n" value="1" <?= $wifi_n == 1 ? 'checked="checked"' : '' ?> />
@@ -86,7 +157,7 @@
         </div>
       </div>
 
-      <div class="panel panel-success">
+      <div class="panel panel-success enabled" <?= $service_enabled == 0 ? 'style="display: none"' : '' ?>>
         <div class="panel-heading">
           <h3 class="panel-title" data-toggle="tooltip" data-title="<?= T_('Real Internet') ?>"><?= T_("IPv6") ?></h3>
         </div>
@@ -123,7 +194,7 @@
         </div>
       </div>
 
-      <div class="panel panel-danger">
+      <div class="panel panel-danger enabled" <?= $service_enabled == 0 ? 'style="display: none"' : '' ?>>
         <div class="panel-heading">
           <h3 class="panel-title" data-toggle="tooltip" data-title="<?= T_('Old Internet') ?>"><?= T_("IPv4") ?></h3>
         </div>
@@ -154,7 +225,18 @@
 
       <div class="form-group">
         <div style="text-align: center">
+<?php if($is_connected_through_hotspot): ?>
+          <div class="alert alert-dismissible alert-warning fade in" role="alert" id="saveconfirmation">
+            <strong><?= T_('Notice') ?>:</strong> <?= T_("You are currently connected through the wifi hotspot. Please, confirm the reloading, wait for the wifi disconnect/reconnect and go back here to check that everything is okay.") ?>
+            <div id="confirm">
+              <button type="submit" class="btn btn-default" data-toggle="tooltip" id="save" data-title="<?= T_('Reloading may take a few minutes. Be patient.') ?>"><?= T_('Confirm') ?></button> <img src="public/img/loading.gif" id="save-loading" alt="Loading..." />
+            </div>
+          </div>
+
+          <button type="button" class="btn btn-default" id="saveconfirm"><?= T_('Save and reload') ?></button>
+<?php else: ?>
           <button type="submit" class="btn btn-default" data-toggle="tooltip" id="save" data-title="<?= T_('Reloading may take a few minutes. Be patient.') ?>"><?= T_('Save and reload') ?></button> <img src="public/img/loading.gif" id="save-loading" alt="Loading..." />
+<?php endif; ?>
         </div>
       </div>
     </form>