admin3.cgi 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. #!/usr/bin/haserl --shell=/bin/bash --upload-limit=32768 --upload-dir=/tmp
  2. <%# upload limit: 32Mb %>
  3. <%
  4. ## SuperGlue project | http://superglue.it | 2014-2015 | GPLv3
  5. ## http://git.superglue.it/superglue/serverfiles
  6. ##
  7. ## admin2.cgi - control panel for Superglue personal server
  8. ##
  9. ## example POST request:
  10. ## curl --data-urlencode 'key=value' http://host/uri
  11. ##
  12. ## returns: 200 (+ output of operation) on success
  13. ## 406 (+ error message in debug mode) on error
  14. readonly _WWW='/www'
  15. readonly _PWDFILE="/opt/lib/htpasswd"
  16. readonly _HOSTPSK='/opt/lib/host.psk'
  17. readonly _TMP='/tmp'
  18. readonly _LOG="${_WWW}/log/admin.log"
  19. readonly _SCRIPTS='/opt/lib/scripts'
  20. readonly _DEBUG=1
  21. readonly _IFS=$IFS
  22. err() {
  23. _ERR="$?"
  24. [[ "$_ERR" -gt 0 ]] || return 0
  25. logThis "$1"
  26. headerPrint "${2:='400'}"
  27. exit "$_ERR"
  28. }
  29. logThis() {
  30. [[ "$_DEBUG" -gt 0 ]] || return 0
  31. local _TYPE='I'
  32. [[ "$_ERR" -eq 0 ]] || _TYPE='E'
  33. local _TIME; printf -v _TIME '%(%Y-%m-%d %H:%M:%S)T' -1
  34. printf '%b\n' "$_TIME: [$_TYPE] ${@} " >> "$_LOG"
  35. [[ "$_DEBUG" -le 1 ]] || printf '%b\n' "[verbose] $_TYPE ${1}"
  36. return $_ERR
  37. }
  38. headerPrint() {
  39. case "$1" in
  40. 200|'') printf '%s\r\n' 'Status: 200 OK';;
  41. 301) printf '%b' "Status: 301 Moved Permanently\r\nLocation: ${HTTP_REFERER:=$2}\r\n";;
  42. 302) printf '%s\r\n' 'Status: 302 Found' "Location: $2";;
  43. 403) printf '%b' 'Status: 403 Forbidden\r\n';;
  44. 405) printf '%b' 'Status: 405 Method Not Allowed\r\n';;
  45. 406) printf '%b' 'Status: 406 Not Acceptable\r\n';;
  46. *) printf '%b' 'Status: 400 Bad Request\r\n';;
  47. esac
  48. printf '%b' 'Content-Type: text/html\r\n\r\n';
  49. }
  50. ## faster echo
  51. _echo() {
  52. printf "%s\r\n" "${*}"
  53. }
  54. urlDec() {
  55. local value=${*//+/%20}
  56. for part in ${value//%/ \\x}; do
  57. printf "%b%s" "${part:0:4}" "${part:4}"
  58. done
  59. }
  60. ## only useful for debugging (remove?)
  61. setQueryVars() {
  62. if [[ "$_DEBUG" -gt 0 ]]; then
  63. _VARS=( ${!POST_*} )
  64. local v
  65. for v in ${_VARS[@]}; do
  66. logThis "$v=${!v}"
  67. done
  68. fi
  69. }
  70. getQueryFile() {
  71. local _UPLD="${HASERL_fwupload_path##*/}"
  72. logThis "'multipart': decoding stream"
  73. mv "$_TMP/$_UPLD" "$_TMP/fwupload.bin" 2>/dev/null || _ERR=$?
  74. if [[ $_ERR -gt 0 ]]; then
  75. showMesg 'Firmware upload has failed' '60' 'Reboot your Superglue server and try again'
  76. fi
  77. }
  78. validIp() {
  79. local _IP=$1
  80. local _RET=1
  81. if [[ $_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  82. OIFS=$IFS
  83. IFS='.'
  84. _IP=($_IP)
  85. IFS=$OIFS
  86. [[ ${_IP[0]} -le 255 && ${_IP[1]} -le 255 && ${_IP[2]} -le 255 && ${_IP[3]} -le 255 ]]
  87. _RET=$?
  88. fi
  89. return $_RET
  90. }
  91. pwdChange() {
  92. local _USER='admin'
  93. local _REALM='superglue'
  94. [[ -e $_PWDFILE ]] || showMesg 'Password file not found'
  95. [[ -z "${POST_pwd##$POST_pwdd}" ]] || showMesg 'Passwords did not match'
  96. [[ ${#POST_pwd} -ge 6 ]] || showMesg 'Password must be at least 6 characters long'
  97. local _HASH=$(printf '%s' "$_USER:$_REALM:${POST_pwd}" | md5sum | cut -b -32) &&
  98. printf '%b' "${POST_pwd}\n${POST_pwd}\n" | passwd root &&
  99. printf '%b' "$_USER:$_REALM:$_HASH\n" > $_PWDFILE &&
  100. showMesg 'Password is changed' '2' ||
  101. showMesg 'Password change failed!' '5'
  102. }
  103. lanAddr() {
  104. logThis "new LAN addr is: $POST_lanipaddr"
  105. validIp $POST_lanipaddr || showMesg 'Not valid network address'
  106. doUci set lanipaddr $POST_lanipaddr &&
  107. doUci commit network &&
  108. dtach -n -zE $_SCRIPTS/net-restart.sh &>/dev/null &&
  109. showMesg 'New network address is set' '30' "Your server is now accessible under <a href='http://superglue.local/admin'>http://superglue.local/admin</a>" ||
  110. showMesg 'Setting network address failed'
  111. }
  112. wanSet() {
  113. if [[ ! -z $POST_wanifname ]]; then
  114. ## eth and wlan wan cases are different!
  115. ## eth wan requires:
  116. ## config interface 'wan'
  117. ## option proto 'dhcp'
  118. ## option ifname 'eth0'
  119. ##
  120. ## wlan wan requires:
  121. ## config interface 'wan'
  122. ## option proto 'dhcp' (and no 'option ifname' specified!)
  123. logThis "wan.ifname=$POST_wanifname"
  124. if [[ $POST_wanifname == 'eth0' ]]; then
  125. doUci set wanifname $POST_wanifname
  126. doUci set wanwifacedis '1'
  127. elif [[ $POST_wanifname == 'wlan1' ]]; then
  128. doUci set wanifname ''
  129. doUci set wanwifacedis ''
  130. fi
  131. if [[ $POST_wanproto == 'dhcp' ]]; then
  132. doUci set wanproto dhcp
  133. doUci set wanipaddr ''
  134. doUci set wanmask ''
  135. doUci set wangw ''
  136. doUci set wandns ''
  137. elif [[ $POST_wanproto == 'static' ]]; then
  138. logThis "wan.ipaddr=$POST_wanipaddr"
  139. validIp $POST_wanipaddr || showMesg 'Our IP address is not valid' '3' 'make sure to use correct address notation'
  140. validIp $POST_wangw || showMesg 'Gateway is not a valid IP address' '3' 'make sure to use correct address notation'
  141. validIp $POST_wandns || showMesg 'DNS is not a valid IP address' '3' 'make sure to use correct address notation'
  142. doUci set wanproto static
  143. doUci set wanipaddr $POST_wanipaddr
  144. doUci set wanmask '255.255.255.0' ## fix me
  145. doUci set wangw $POST_wangw
  146. doUci set wandns $POST_wandns
  147. fi
  148. if [[ $POST_wanifname == 'wlan1' ]]; then
  149. ssidChange || showMesg 'wanSet: Wireless configuration failed'
  150. else
  151. doUci commit network &&
  152. doUci commit wireless &&
  153. dtach -n -zE $_SCRIPTS/net-restart.sh &>/dev/null
  154. fi
  155. _ERR=$?
  156. [[ $_ERR -eq 0 ]] &&
  157. showMesg 'Internet connection is being configured' '25' 'check your Internet connection on completion' ||
  158. showMesg 'Configuring Internet connection failed' '5'
  159. fi
  160. }
  161. ssidChange() {
  162. ## check for iface
  163. [[ $POST_iface =~ ^('wan'|'lan')$ ]] || showMesg 'Error changing wireless settings' '5' 'unknown or unconfigured interface'
  164. logThis "$POST_iface is being set"
  165. _p=$POST_iface
  166. ## default enc for now
  167. local _enc='psk2'
  168. if [[ $POST_iface == 'wan' ]]; then
  169. local _mode='sta'
  170. local _ssid="${POST_wanssid}"
  171. local _key="${POST_wankey}"
  172. else
  173. local _mode='ap'
  174. local _ssid="${POST_lanssid}"
  175. local _key="${POST_lankey}"
  176. fi
  177. #logThis "ssid: $_ssid [$_mode], key: $_key [$_enc]"
  178. #logThis $POST_wanssid
  179. [[ ${#_ssid} -ge 3 ]] || showMesg 'SSID must be at least 3 characters long'
  180. doUci set $_p'ssid' "${_ssid}"
  181. if [[ -z $_key ]]; then
  182. ## if key is empty set encryption to none and remove key
  183. doUci set $_p'key' && doUci set $_p'enc' 'none'
  184. _ERR=$?
  185. else
  186. [[ ${#_key} -ge 8 ]] || showMesg 'Passphrase must be at least 8 characters long'
  187. doUci set $_p'key' "${_key}" && doUci set $_p'enc' "${_enc}"
  188. fi
  189. [[ $_ERR -eq 0 ]] || showMesg 'ssidChange: Wireless configuration failed'
  190. if [[ $POST_iface == 'lan' ]]; then
  191. if [[ "$(doUci get lanipaddr)" != "${POST_lanipaddr}" ]]; then
  192. logThis 'local IP was changed'
  193. lanAddr
  194. fi
  195. fi
  196. doUci commit wireless
  197. _ERR=$?
  198. [[ $_ERR -eq 0 ]] &&
  199. dtach -n -zE $_SCRIPTS/net-restart.sh &>/dev/null ||
  200. showMesg 'Wireless configuration failed' '5'
  201. [[ $POST_iface == 'lan' ]] &&
  202. showMesg 'Local network configuration is progress' '30' 'check your connection on completion' || return 0
  203. ## in this case wanSet() handles success message
  204. }
  205. showMesg() {
  206. local _RET=$?
  207. local _MSG=$1
  208. local _TIMEOUT=$2
  209. local _SUBMSG=$3
  210. ## if set, global _ERR value prevails
  211. [[ $_ERR -gt $_RET ]] && _RET=$_ERR
  212. _MSG=${_MSG:='Configuration'}
  213. _TIMEOUT=${_TIMEOUT:='5'}
  214. _SUBMSG="${_SUBMSG} <span id='timeout'>${_TIMEOUT}</span> seconds to get ready.."
  215. if [[ $_RET -gt 0 ]]; then
  216. local _TYPE='ERROR: '
  217. headerPrint 406
  218. else
  219. local _TYPE='OK: '
  220. headerPrint 200
  221. fi
  222. htmlHead "<meta http-equiv='refresh' content='${_TIMEOUT};url=http://${HTTP_HOST}/admin'>"
  223. _echo "<body>
  224. <h1>Superglue control panel</h1>
  225. <img src='http://${HTTP_HOST}/resources/img/superglueLogo.png' class='logo'>
  226. <hr>
  227. <h2 style='display:inline'>$_TYPE $_MSG</h2>
  228. <span style='display:block'>$_SUBMSG</span>
  229. <hr>
  230. </body>
  231. <script type='text/javascript'>(function(e){var t=document.getElementById(e);var n=t.innerHTML;var r=setInterval(function(){if(n==0){t.innerHTML='0';clearInterval(r);return}t.innerHTML=n;n--},1e3)})('timeout')
  232. </script>
  233. </html>"
  234. exit $_RET
  235. }
  236. updateFw() {
  237. local _FWFILE="${_TMP}/fwupload.bin"
  238. _OUT="$(sysupgrade -T $_FWFILE 2>&1)" ||
  239. { _ERR=$?; rm -rf $_FWFILE; showMesg 'This is not a firmware!' '3' "$_OUT"; }
  240. [[ $POST_fwreset == 'on' ]] && { _FWRESET='-n'; logThis 'fw reset requested'; }
  241. ## using dtach to prevent sysupgrade getting killed
  242. dtach -n -zE sysupgrade $_FWRESET $_FWFILE 2>&1 &&
  243. showMesg 'Firmware update is in progress..' '120' 'DO NOT INTERRUPT!' ||
  244. { _ERR=$?; rm -rf $_FWFILE; showMesg 'Firmware update failed..' '3'; }
  245. }
  246. usbInit() {
  247. . $_SCRIPTS/usb-part.sh
  248. _OUT="$(usbPart)" &&
  249. showMesg 'USB storage initialization is completed' '30' ||
  250. showMesg "USB init failed!\n$_OUT"
  251. # logThis 'usb init..'
  252. }
  253. rebootNow() {
  254. logThis "reboot: now!"
  255. # reboot
  256. reboot -d 3 || reboot -f
  257. showMesg 'Rebooting..' '60'
  258. }
  259. upTime() {
  260. local _T="$(uptime)" &&
  261. { headerPrint 200; printf '%b' "$_T\n"; exit 0; } ||
  262. headerPrint 406
  263. }
  264. iwScan() {
  265. . $_SCRIPTS/iw-scan.sh
  266. headerPrint 200
  267. iwScan
  268. exit 0
  269. }
  270. findUsbstor() {
  271. local _P='/sys/block/'
  272. local _D _DEV
  273. for _D in ${_P}sd*; do
  274. _DEV=$(readlink -f ${_D}/device)
  275. if [[ ${_DEV/usb} != $_DEV ]]; then
  276. _USBDEV="/dev/${_D/$_P}"
  277. fi
  278. done
  279. [[ $_USBDEV ]] || return 1
  280. }
  281. storageInfo() {
  282. if mountpoint -q $_WWW; then
  283. IFS=$'\n' _STOR=( $(df -h $_WWW) ) IFS=$_IFS
  284. _STOR=( ${_STOR[1]} )
  285. else
  286. return 1
  287. fi
  288. }
  289. swapInfo() {
  290. IFS=$'\n' _SWAP=( $(swapon -s) ) IFS=$_IFS
  291. if [[ ${_SWAP[1]} ]]; then
  292. IFS=$'\t' _SWAP=( ${_SWAP[1]} ) IFS=$_IFS
  293. ## for the lack of floats add trailing 0
  294. ## divide by 1023 and split last digit by a period
  295. _SWAP[1]="$((${_SWAP[1]}0/1023))"
  296. _SWAP[1]="${_SWAP[1]%?}.${_SWAP[1]/??}M"
  297. else
  298. unset _SWAP
  299. return 1
  300. fi
  301. }
  302. trimSpaces() {
  303. local v="$*"
  304. v="${v#"${v%%[![:space:]]*}"}"
  305. v="${v%"${v##*[![:space:]]}"}"
  306. return "$v"
  307. }
  308. sgDdns() {
  309. [[ $POST_sgddnsdomain && $POST_sgddnssubdomain ]] || showMesg 'All values must be set!'
  310. [[ ! "$POST_sgddnssubdomain" =~ [^a-zA-Z0-9$] ]] || showMesg 'Invalid domain name'
  311. [[ ! "$POST_sgddnsupdateurl" == '' ]] || showMesg 'Invalid update URL'
  312. local _CLIENT _DOMAIN _JSON _UPDATEURL _MSG _HTTPCODE _x
  313. [[ -r $_HOSTPSK ]] || showMesg 'Local PSK is not available'
  314. ## produce md5 hash from client PSK
  315. hashClient() {
  316. local _L
  317. while read -r _L; do
  318. printf "%s" ${_L%%[\#\-]*}
  319. done < $_HOSTPSK | md5sum
  320. }
  321. read -r _CLIENT _x < <(hashClient)
  322. logThis "sgvpn client hash: $_CLIENT"
  323. _UPDATEURL="$POST_sgddnsupdateurl"
  324. doUci set sgddnssubdomain "${POST_sgddnssubdomain,,}" &&
  325. doUci set sgddnsdomain "${POST_sgddnsdomain,,}" &&
  326. doUci set sgddnsclient "$_CLIENT" &&
  327. doUci set sgddnsurl "$_UPDATEURL" &&
  328. doUci set sgddnsenable '1' || showMesg 'Error setting DDNS configuration'
  329. doUci commit dyndns
  330. ## attempt first update to check if domain is available and everything checks out
  331. IFS=$'\t'; read -r _MSG _HTTPCODE < <($_SCRIPTS/dyndns-update.sh); IFS=$_IFS
  332. $_MSG="${_MSG:='Unknown error'}"
  333. logThis "sgvpn check: $_MSG"
  334. if [[ ! $_HTTPCODE == 200 ]]; then
  335. _ERR=1
  336. logThis 'error in dns update, disabling configuration'
  337. doUci set sgddnsdomain ''
  338. doUci set sgddnssubdomain ''
  339. doUci set sgddnsclient ''
  340. doUci set sgddnsurl ''
  341. doUci set sgddnsenable '0'
  342. doUci commit dyndns
  343. showMesg "$_MSG" '10'
  344. fi
  345. showMesg 'Domain configuration is in progress..' '10' 'Your address will become available right away'
  346. }
  347. sgOpenvpn() {
  348. logThis "enabling SG openvpn"
  349. if [[ $(doUci get sgopenvpnenable) == '0' ]]; then
  350. doUci set sgopenvpnenable '1' &&
  351. /etc/init.d/openvpn start &&
  352. showMesg 'VPN service enabled' '5'
  353. else
  354. doUci set sgopenvpnenable '0' &&
  355. /etc/init.d/openvpn stop &&
  356. showMesg 'VPN service disabled' '5'
  357. fi
  358. showMesg 'VPN configuration failed' '5' 'make sure your device is online'
  359. }
  360. showMesg2() {
  361. local _MSG=$1
  362. local _TIMEOUT=$2
  363. local _SUBMSG=$3
  364. _MSG=${_MSG:='Configuration'}
  365. _TIMEOUT=${_TIMEOUT:='5'}
  366. _SUBMSG="${_SUBMSG} <span id='timeout'>${_TIMEOUT}</span> seconds to get ready.."
  367. headerPrint 200
  368. htmlHead
  369. # htmlHead "<meta http-equiv='refresh' content='${_TIMEOUT};url=http://${HTTP_HOST}/admin'>"
  370. _echo "<body>
  371. <h1>Superglue control panel</h1>
  372. <img src='http://${HTTP_HOST}/resources/img/superglueLogo.png' class='logo'>
  373. <hr>
  374. <h2 style='display:inline'>$_MSG</h2>
  375. <span style='display:block'>$_SUBMSG</span>
  376. <hr>
  377. </body>
  378. <script type='text/javascript'>(function(e){var t=document.getElementById(e);var n=t.innerHTML;var r=setInterval(function(){if(n==0){t.innerHTML='0';clearInterval(r);return}t.innerHTML=n;n--},1e3)})('timeout')
  379. </script>
  380. </html>"
  381. }
  382. testRun() {
  383. logThis 'starting test '
  384. showMesg2 'Running test'
  385. sleep 2; logThis 'running test'; sleep 5
  386. # printf '%s' "Location: /admin/error/\r\n"
  387. # printf '%b' "Status: 301 Moved Permanently\r\nLocation: http://${HTTP_HOST}/admin/error\r\n"
  388. # exit
  389. headerPrint '302' "http://${HTTP_HOST}/admin/error"
  390. # exit
  391. # showMesg 'Test run'
  392. }
  393. doUci() {
  394. local _CMD=''
  395. local _ARG=''
  396. case $1 in
  397. get|set|commit) _CMD=$1;;
  398. *) logThis 'bad UCI command'; headerPrint 405; echo 'bad UCI command'; exit 1 ;;
  399. esac
  400. case $2 in
  401. lanssid) _ARG='wireless.@wifi-iface[0].ssid';;
  402. lanenc) _ARG='wireless.@wifi-iface[0].encryption';;
  403. lankey) _ARG='wireless.@wifi-iface[0].key';;
  404. wanwifacedis) _ARG='wireless.@wifi-iface[1].disabled';;
  405. wanssid) _ARG='wireless.@wifi-iface[1].ssid';;
  406. wanenc) _ARG='wireless.@wifi-iface[1].encryption';;
  407. wankey) _ARG='wireless.@wifi-iface[1].key';;
  408. lanipaddr) _ARG='network.lan.ipaddr';;
  409. wanifname) _ARG='network.wan.ifname';;
  410. wanproto) _ARG='network.wan.proto';;
  411. wanipaddr) _ARG='network.wan.ipaddr';;
  412. wanmask) _ARG='network.wan.netmask';;
  413. wangw) _ARG='network.wan.gateway';;
  414. wandns) _ARG='network.wan.dns';;
  415. sgddnsenable) _ARG='dyndns.superglue.enable';;
  416. sgddnsurl) _ARG='dyndns.superglue.updateurl';;
  417. sgddnsclient) _ARG='dyndns.superglue.client';;
  418. sgddnssubdomain) _ARG='dyndns.superglue.subdomain';;
  419. sgddnsdomain) _ARG='dyndns.superglue.domain';;
  420. sgopenvpnenable) _ARG='openvpn.superglue.enable';;
  421. *) if [[ $_CMD == 'commit' ]]; then
  422. _ARG=$2
  423. else
  424. logThis "bad UCI entry: $2"
  425. _ERR=1
  426. showMesg 'bad UCI entry'
  427. fi ;;
  428. esac
  429. if [[ $_CMD == 'get' ]]; then
  430. if [ ! -z $_ARG ]; then
  431. /sbin/uci -q get $_ARG || return $?
  432. fi
  433. fi
  434. if [[ $_CMD == 'set' ]]; then
  435. local _VAL=$3
  436. if [ -z $_VAL ]; then
  437. logThis "empty $_ARG value, removing record"
  438. /sbin/uci delete $_ARG || ( echo "uci delete $_ARG: error"; exit 1; )
  439. fi
  440. if [ ! -z $_ARG ]; then
  441. logThis "setting $_ARG value"
  442. /sbin/uci set $_ARG=$_VAL || ( echo "uci set $_ARG: error"; exit 1; )
  443. fi
  444. fi
  445. if [[ $_CMD == 'commit' ]]; then
  446. /sbin/uci commit $_ARG || echo "uci commit $_ARG: error"
  447. fi
  448. }
  449. ## call with argument to inject additional lines
  450. ## ie: htmlhead "<meta http-equiv='refresh' content='2;URL=http://${HTTP_REFERER}'>"
  451. htmlHead() {
  452. _echo "<!-- obnoxious code below, keep your ports tight -->
  453. <!doctype html>
  454. <html>
  455. <head>
  456. <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
  457. <meta http-equiv='Cache-Control' content='no-cache, no-store, must-revalidate' />
  458. <meta http-equiv='Pragma' content='no-cache' />
  459. <meta http-equiv='Expires' content='0' />
  460. <link rel='icon' href='http://${HTTP_HOST}/resources/img/favicon.ico' type='image/x-icon' />
  461. <title>Superglue | Control panel</title>
  462. <link rel='stylesheet' type='text/css' href='http://${HTTP_HOST}/resources/admin/admin.css' />
  463. $@
  464. </head>"
  465. }
  466. footerBody() {
  467. _echo "</body>
  468. <script type='text/javascript' src='http://${HTTP_HOST}/resources/admin/admin.js'></script>
  469. </html>"
  470. }
  471. if [[ "${REQUEST_METHOD^^}" == "POST" ]]; then
  472. [[ $CONTENT_LENGTH -gt 0 ]] || err 'content length is zero, 301 back to referer' '301'
  473. case "${CONTENT_TYPE^^}" in
  474. APPLICATION/X-WWW-FORM-URLENCODED*) setQueryVars;;
  475. MULTIPART/FORM-DATA*) getQueryFile;;
  476. *) _ERR=1; _OUT='this is not a post';;
  477. esac
  478. case $REQUEST_URI in
  479. *pwdchange) pwdChange;;
  480. *ssidchange) ssidChange;;
  481. *lanaddr) lanAddr;;
  482. *updatefw) updateFw;;
  483. *usbinit) usbInit;;
  484. *rebootnow) rebootNow;;
  485. *wan) wanSet;;
  486. *uptime) upTime;;
  487. *iwscan) iwScan;;
  488. *sgddns) sgDdns;;
  489. *sgvpn) sgOpenvpn;;
  490. *testrun) testRun;;
  491. *) logThis 'bad action'; headerPrint 405;
  492. echo 'no such thing'; exit 1;;
  493. esac
  494. fi
  495. ## if URL is not (just) /admin
  496. #if [[ "${REQUEST_METHOD^^}" == "GET" ]]; then
  497. if [[ "${REQUEST_URI/\/admin\//}" ]]; then
  498. headerPrint '301' '/admin/'
  499. fi
  500. #fi
  501. headerPrint '200'
  502. htmlHead
  503. read sgver < /etc/superglue_version
  504. read devmod < /etc/superglue_model
  505. read openwrt < /etc/openwrt_version
  506. . /opt/lib/scripts/jshn-helper.sh
  507. ## this does not work when iface isn't configured
  508. IFS=','
  509. wan=( $(ifaceStat wan) )
  510. IFS=$_IFS
  511. sgvpn=$(doUci get sgopenvpnenable)
  512. ddomain=$(doUci get sgddnsdomain)
  513. dsubdomain=$(doUci get sgddnssubdomain)
  514. wanifname=${wan[3]}
  515. wanproto=$(doUci get wanproto)
  516. wanipaddr=${wan[0]}
  517. wangw=${wan[2]}
  518. wandns=${wan[5]}
  519. wanuptime=${wan[4]}
  520. wanssid=$(doUci get wanssid)
  521. wankey=$(doUci get wankey)
  522. %>
  523. <body>
  524. <h1>Superglue control panel</h1>
  525. <img src='http://<% _echo "${HTTP_HOST}" %>/resources/img/superglueLogo.png' class='logo'>
  526. <section class='inert'>
  527. <span style='display:block;'><% printf "System version: %s | Device: %s | OpenWRT: %s" "$sgver" "$devmod" "$openwrt" %></span>
  528. <span style='display:block;' id='uptime'><% uptime %></span>
  529. </section>
  530. <section>
  531. <h2>Test run</h2>
  532. <form method='post' action='/admin/testrun' name='test' class='elem' id='wanconf'>
  533. <input type='hidden' name='testrun' value='go' class='inline'>
  534. <input type='submit' value='Run' class='inline'>
  535. </form>
  536. </section>
  537. <section>
  538. <h2>Internet connection</h2>
  539. <form method='post' action='/admin/wan' name='wan' class='elem' id='wanconf'>
  540. <div style='display:inline-flex'>
  541. <div style='display:inline-block;'>
  542. <select name='wanifname' id='wanifname' style='display:block'>
  543. <option value='eth0' id='eth' <% ( [[ $wanifname =~ ('eth') ]] && _echo 'selected' ) %> >Wired (WAN port)</option>
  544. <option value='wlan1' id='wlan' <% ( [[ $wanifname =~ ('wlan') ]] && _echo 'selected' ) %> >Wireless (WiFi)</option>
  545. </select>
  546. <fieldset id='wanwifi' <% ( [[ $wanifname =~ ('wlan') ]] && _echo "class='show elem'" || _echo "class='hide elem'" ) %>>
  547. <select name='wanssid' id='wanssid' class='elem' style='display:block'>
  548. <% if [[ -z $wanssid ]]; then
  549. _echo "<option id='scan' disabled>select a network..</option>"
  550. else
  551. _echo "<option id=$wanssid selected>$wanssid</option>"
  552. fi %>
  553. </select>
  554. <input type='password' name='wankey' placeholder='passphrase' value='<% _echo $wankey %>'>
  555. </fieldset>
  556. <span class='help'>help</span>
  557. </div>
  558. <div style='display:inline-block;'>
  559. <select name='wanproto' id='wanproto' style='display:block'>
  560. <option value='dhcp' name='dhcp' id='dhcp' <% ([[ "$wanproto" == 'dhcp' ]] && _echo 'selected') %>>Automatic (DHCP)</option>
  561. <option value='static' name='stat' id='stat' <% ([[ "$wanproto" == 'static' ]] && _echo 'selected') %>>Manual (Static IP)</option>
  562. </select>
  563. <fieldset id='wanaddr' class='elem'>
  564. <input type='text' name='wanipaddr' id='wanipaddr' value='<% _echo $wanipaddr %>' <% ( [[ $wanproto =~ ('dhcp') ]] && _echo "readonly" ) %> placeholder='ip address'>
  565. <input type='text' name='wangw' id='wangw' value='<% _echo $wangw %>' <% ( [[ $wanproto =~ ('dhcp') ]] && _echo "readonly" ) %> placeholder='gateway/router'>
  566. <input type='text' name='wandns' id='wandns' value='<% _echo $wandns %>' <% ( [[ $wanproto =~ ('dhcp') ]] && _echo "readonly" ) %> placeholder='dns server'>
  567. </fieldset>
  568. </div>
  569. </div>
  570. <div>
  571. <input type='hidden' name='iface' value='wan' class='inline'>
  572. <input type='submit' id='wansubmit' value='Apply' class='inline'>
  573. </form>
  574. <form method='post' action='/admin/sgvpn' class='inline'>
  575. <input type='hidden' name='sgvpn' value='toggle' class='inline'>
  576. <input type='submit' value='<% [[ "$sgvpn" == '1' ]] && _echo 'Disable Superglue VPN service' || _echo 'Enable Superglue VPN service' %>' class='inline'>
  577. </form>
  578. </div>
  579. <span class='help'>help</span>
  580. </section>
  581. <section>
  582. <h2>Domain name</h2>
  583. <form method='post' action='/admin/sgddns' name='sgddns' id='sgddns'>
  584. <div style='display:inline-flex'>
  585. <div style='display:inline-block;'>
  586. <input type='text' name='sgddnssubdomain' placeholder='domain name' value='<% _echo $dsubdomain %>' class='inline'>
  587. </div>
  588. <div style='display:inline-block;'>
  589. <select name='sgddnsdomain' class='inline'>
  590. <option value='spgl.it' <% [[ "$ddomain" == 'spgl.it' ]] && _echo 'selected' %>>.spgl.it</option>
  591. <option value='spgl.cc' <% [[ "$ddomain" == 'spgl.cc' ]] && _echo 'selected' %>>.spgl.cc</option>
  592. <option value='superglue.it' <% [[ "$ddomain" == 'superglue.it' ]] && _echo 'selected' %>>.superglue.it</option>
  593. </select>
  594. </div>
  595. </div>
  596. <input type='submit' name='submit' value="Apply">
  597. <input type='hidden' name='sgddnsupdateurl' value='https://superglue.it/ddns/update'>
  598. </form>
  599. </section>
  600. <section>
  601. <h2>Local wireless network</h2>
  602. <form method='post' action='/admin/ssidchange'>
  603. <div style='display:inline-flex'>
  604. <div style='display:inline-block;'>
  605. <input type='text' name='lanssid' value='<% doUci get lanssid %>'>
  606. <input type='password' name='lankey' value='<% doUci get lankey %>'>
  607. </div>
  608. <div style='display:inline-block;'>
  609. <input type='text' name='lanipaddr' value='<% doUci get lanipaddr %>'>
  610. <input type='hidden' name='iface' value='lan'>
  611. </div>
  612. </div>
  613. <input type='submit' value='Apply' data-wait='Configuring..'>
  614. </form>
  615. <span class='help'>help</span>
  616. </section>
  617. <section>
  618. <h2>USB storage</h2>
  619. <% if findUsbstor; then %>
  620. <% if storageInfo; then %>
  621. <div>File storage: <% _echo "${_STOR[2]} used, ${_STOR[3]} available" %></div>
  622. <div>Swap: <% swapInfo && _echo "${_SWAP[1]}" || _echo '<b>n/a</b>' %></div>
  623. <% else %>
  624. <div>USB storage device must be initialized</div>
  625. <form method='post' action='/admin/usbinit'>
  626. <input type='hidden' name='dev' value='<% _echo $_USBDEV %>'>
  627. <input type='submit' value='Initialize'>
  628. </form>
  629. <% fi %>
  630. <% else %>
  631. <div><h3>USB storage device not found!</h3>Please check and try again</div>
  632. <% fi %>
  633. <span class='help'>help</span>
  634. </section>
  635. <section>
  636. <h2>Change password</h2>
  637. <form method='post' action='/admin/pwdchange'>
  638. <div style='display:inline-flex'>
  639. <div style='display:inline-block;'>
  640. <input type='text' name='usr' value='admin' readonly>
  641. </div>
  642. <div style='display:inline-block;'>
  643. <input type='password' name='pwd' placeholder='password' value=''>
  644. <input type='password' name='pwdd' placeholder='password again' value=''>
  645. </div>
  646. </div>
  647. <input type='submit' value='Apply'>
  648. </form>
  649. <span class='help'>help</span>
  650. </section>
  651. <section>
  652. <h2>Update firmware</h2>
  653. <form method='post' action='/admin/updatefw' enctype='multipart/form-data'>
  654. <div id='uploadbox'>
  655. <input id='uploadfile' placeholder='Select a file..' class='elem' disabled='disabled'>
  656. <input id='uploadbtn' class='elem' name='fwupload' type='file'>
  657. </div>
  658. <div style='display:inline-block;'>
  659. <input type='checkbox' name='fwreset' id='fw-resetbox' />
  660. <label for='fw-resetbox'>Reset all settings</label>
  661. </div>
  662. <input type='submit' value='Upload' data-wait='Uploading, do NOT interrupt!'>
  663. </form>
  664. <span class='help'>help</span>
  665. </section>
  666. <section>
  667. <h2></h2>
  668. <form action='/admin/rebootnow' method='post' class='inline'>
  669. <input type='hidden' name='reboot' value='now' class='inline'>
  670. <input type='submit' value='Reboot' class='inline'>
  671. </form>
  672. <form method='post' action='http://logout@<% _echo ${HTTP_HOST} %>/admin' class='inline'>
  673. <input type='submit' value='Logout' class='inline'>
  674. </form>
  675. </section>
  676. <div style='height:200px' name='big-spacer'></div>
  677. <section>
  678. <h2>Under the hood</h2>
  679. <h4>Memory</h4>
  680. <pre><% free %></pre>
  681. <hr>
  682. <h4>Storage</h4>
  683. <pre><% df -h %></pre>
  684. <hr>
  685. <h4>Recent log entries</h4>
  686. <pre><% tail -n10 /www/log/*.log %></pre>
  687. <hr>
  688. <h4>Environment</h4>
  689. <pre><% env %></pre>
  690. <hr>
  691. </section>
  692. <%
  693. footerBody
  694. exit 0
  695. %>