freedombone-controlpanel 66KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035
  1. #!/bin/bash
  2. #
  3. # .---. . .
  4. # | | |
  5. # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-.
  6. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-'
  7. # ' ' --' --' -' - -' ' ' -' -' -' ' - --'
  8. #
  9. # Freedom in the Cloud
  10. #
  11. # Administrator control panel for the Freedombone system
  12. #
  13. # License
  14. # =======
  15. #
  16. # Copyright (C) 2015-2018 Bob Mottram <bob@freedombone.net>
  17. #
  18. # This program is free software: you can redistribute it and/or modify
  19. # it under the terms of the GNU Affero General Public License as published by
  20. # the Free Software Foundation, either version 3 of the License, or
  21. # (at your option) any later version.
  22. #
  23. # This program is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU Affero General Public License for more details.
  27. #
  28. # You should have received a copy of the GNU Affero General Public License
  29. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  30. PROJECT_NAME='freedombone'
  31. export TEXTDOMAIN=${PROJECT_NAME}-controlpanel
  32. export TEXTDOMAINDIR="/usr/share/locale"
  33. if [[ $USER != 'root' ]]; then
  34. # show the user version of the control panel
  35. #${PROJECT_NAME}-controlpanel-user
  36. controluser
  37. exit 0
  38. fi
  39. function please_wait {
  40. local str width height length
  41. width=$(tput cols)
  42. height=$(tput lines)
  43. str=$"Please wait"
  44. length=${#str}
  45. clear
  46. tput cup $((height / 2)) $(((width / 2) - (length / 2)))
  47. echo "$str"
  48. tput cup $((height * 3 / 5)) $(((width / 2)))
  49. echo -n ''
  50. }
  51. please_wait
  52. # Start including files
  53. source /usr/local/bin/${PROJECT_NAME}-vars
  54. UTILS_FILES="/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-*"
  55. for f in $UTILS_FILES
  56. do
  57. source "$f"
  58. done
  59. APP_FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  60. for f in $APP_FILES
  61. do
  62. source "$f"
  63. done
  64. # End including files
  65. COMPLETION_FILE="$HOME/${PROJECT_NAME}-completed.txt"
  66. SELECTED_USERNAME=
  67. ADMIN_USER=
  68. UPGRADE_SCRIPT_NAME="${PROJECT_NAME}-upgrade"
  69. UPDATE_DATE_SCRIPT=/usr/bin/updatedate
  70. # Minimum number of characters in a password
  71. MINIMUM_PASSWORD_LENGTH=$(grep 'MINIMUM_PASSWORD_LENGTH=' "/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-passwords" | head -n 1 | awk -F '=' '{print $2}')
  72. # Mumble
  73. MUMBLE_PORT=64738
  74. MUMBLE_ONION_PORT=8095
  75. SSH_PORT=2222
  76. # outgoing SMTP proxy
  77. SMTP_PROXY_ENABLE=$'no'
  78. SMTP_PROXY_PROTOCOL='smtps'
  79. SMTP_PROXY_SERVER='mail.myispdomain'
  80. SMTP_PROXY_PORT=465
  81. SMTP_PROXY_USERNAME=''
  82. SMTP_PROXY_PASSWORD=''
  83. WIFI_INTERFACE=wlan0
  84. WIFI_SSID=
  85. WIFI_TYPE='wpa2-psk'
  86. WIFI_PASSPHRASE=
  87. WIFI_HOTSPOT='no'
  88. WIFI_NETWORKS_FILE="$HOME/${PROJECT_NAME}-wifi.cfg"
  89. USB_DRIVE=sdb
  90. # get default USB from config file
  91. CONFIGURATION_FILE="$HOME/${PROJECT_NAME}.cfg"
  92. read_config_param WIFI_HOTSPOT
  93. read_config_param WIFI_INTERFACE
  94. read_config_param WIFI_TYPE
  95. read_config_param WIFI_SSID
  96. read_config_param WIFI_PASSPHRASE
  97. read_config_param SSH_PORT
  98. read_config_param SMTP_PROXY_ENABLE
  99. read_config_param SMTP_PROXY_PROTOCOL
  100. read_config_param SMTP_PROXY_SERVER
  101. read_config_param SMTP_PROXY_PORT
  102. read_config_param SMTP_PROXY_USERNAME
  103. read_config_param SMTP_PROXY_PASSWORD
  104. read_config_param USB_DRIVE
  105. read_config_param MY_USERNAME
  106. read_config_param ONION_ONLY
  107. if [[ $USB_DRIVE == *"dev"* ]]; then
  108. USB_DRIVE=$(echo ${USB_DRIVE} | awk -F '/' '{print $3}' | sed 's|1||g' | sed 's|2||g')
  109. fi
  110. function any_key {
  111. echo ''
  112. # shellcheck disable=SC2034
  113. read -n1 -rsp $"Press any key to continue..." key
  114. }
  115. function reset_password_tries {
  116. passwords_select_user
  117. if [ ! "$SELECTED_USERNAME" ]; then
  118. return
  119. fi
  120. pam_tally --user "$SELECTED_USERNAME" --reset
  121. dialog --title $"Reset password tries" \
  122. --msgbox $"Password tries have been reset for $SELECTED_USERNAME" 6 60
  123. }
  124. function check_for_updates {
  125. if [ ! -f "/etc/cron.weekly/$UPGRADE_SCRIPT_NAME" ]; then
  126. dialog --title $"Check for updates" \
  127. --msgbox $"Upgrade script was not found" 6 40
  128. return
  129. fi
  130. clear
  131. /etc/cron.weekly/$UPGRADE_SCRIPT_NAME
  132. any_key
  133. }
  134. function add_user {
  135. data=$(mktemp 2>/dev/null)
  136. dialog --backtitle $"Freedombone Control Panel" \
  137. --title $"Add new user" \
  138. --form "\\n" 8 60 3 \
  139. $"Username:" 1 1 "" 1 28 16 15 \
  140. $"ssh public key (optional):" 2 1 "" 2 28 40 10000 \
  141. 2> "$data"
  142. sel=$?
  143. case $sel in
  144. 1) rm -f "$data"
  145. return;;
  146. 255) rm -f "$data"
  147. return;;
  148. esac
  149. new_user_username=$(sed -n 1p < "$data")
  150. new_user_ssh_public_key=$(sed -n 2p < "$data")
  151. rm -f "$data"
  152. if [ ${#new_user_username} -lt 2 ]; then
  153. dialog --title $"New username" \
  154. --msgbox $"No username was given" 6 40
  155. return
  156. fi
  157. if [[ "$new_user_username" == *" "* ]]; then
  158. dialog --title $"Invalid username" \
  159. --msgbox $"The username should not contain any spaces" 6 40
  160. return
  161. fi
  162. if [ ${#new_user_ssh_public_key} -lt 20 ]; then
  163. clear
  164. "${PROJECT_NAME}-adduser" "$new_user_username"
  165. any_key
  166. else
  167. if [[ "$new_user_ssh_public_key" == "ssh-"* ]]; then
  168. clear
  169. "${PROJECT_NAME}-adduser" "$new_user_username" "$new_user_ssh_public_key"
  170. any_key
  171. else
  172. dialog --title $"ssh public key" \
  173. --msgbox $"This does not look like an ssh public key" 6 40
  174. fi
  175. fi
  176. }
  177. function pad_string {
  178. echo -n -e "$1" | sed -e :a -e 's/^.\{1,25\}$/& /;ta'
  179. }
  180. function show_domains {
  181. read_config_param "DEFAULT_DOMAIN_NAME"
  182. echo 'Domains'
  183. echo '======='
  184. echo ''
  185. echo -n -e "$(pad_string 'Name')"
  186. echo -n -e "$(pad_string 'ICANN')"
  187. echo -n -e "$(pad_string 'Tor')"
  188. echo ''
  189. echo '--------------------------------------------------------------------------'
  190. if grep -q "ssh onion domain" "$COMPLETION_FILE"; then
  191. echo -n -e "$(pad_string 'ssh')"
  192. echo -n -e "$(pad_string "${DEFAULT_DOMAIN_NAME}")"
  193. grep 'ssh onion domain' "${COMPLETION_FILE}" | awk -F ':' '{print $2}'
  194. fi
  195. if grep -q "email onion domain" "$COMPLETION_FILE"; then
  196. echo -n -e "$(pad_string 'Email')"
  197. echo -n -e "$(pad_string "${DEFAULT_DOMAIN_NAME}")"
  198. grep 'email onion domain' "${COMPLETION_FILE}" | awk -F ':' '{print $2}'
  199. fi
  200. if grep -q "sks onion domain" "$COMPLETION_FILE"; then
  201. read_config_param "KEYSERVER_DOMAIN_NAME"
  202. echo -n -e "$(pad_string 'SKS')"
  203. echo -n -e "$(pad_string "${KEYSERVER_DOMAIN_NAME}")"
  204. grep 'sks onion domain' "${COMPLETION_FILE}" | awk -F ':' '{print $2}'
  205. fi
  206. # shellcheck disable=SC2068
  207. for app_name in ${APPS_INSTALLED_NAMES[@]}
  208. do
  209. if ! grep -q "SHOW_ON_ABOUT=1" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
  210. continue
  211. fi
  212. # handle the foibles of capitalisation
  213. if ! grep -q "${app_name} domain" "$COMPLETION_FILE"; then
  214. app_name_upper=$(echo "${app_name}" | awk '{print toupper($0)}')
  215. if grep -q "${app_name_upper} domain" "$COMPLETION_FILE"; then
  216. app_name=${app_name_upper}
  217. else
  218. app_name_first_upper="$(tr '[:lower:]' '[:upper:]' <<< "${app_name:0:1}")${app_name:1}"
  219. if grep -q "${app_name_first_upper} domain" "$COMPLETION_FILE"; then
  220. app_name=${app_name_first_upper}
  221. fi
  222. fi
  223. fi
  224. if [ ${#app_name} -gt 0 ]; then
  225. icann_address=$(get_app_icann_address "$app_name")
  226. if grep -q "SHOW_ICANN_ADDRESS_ON_ABOUT=0" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
  227. icann_address='-'
  228. fi
  229. if [[ "$ONION_ONLY" != 'no' ]]; then
  230. if [[ "${icann_address}" != "${LOCAL_NAME}.local" ]]; then
  231. icann_address='-'
  232. fi
  233. fi
  234. onion_address=$(get_app_onion_address "$app_name")
  235. if [ ${#onion_address} -eq 0 ]; then
  236. onion_address="-"
  237. fi
  238. echo -n -e "$(pad_string "${app_name}")"
  239. echo -n -e "$(pad_string "${icann_address}")"
  240. echo "${onion_address}"
  241. if grep -q "mobile${app_name} onion domain" "$COMPLETION_FILE"; then
  242. onion_address=$(get_app_onion_address "${app_name}" "mobile")
  243. echo -n -e "$(pad_string "${app_name} (mobile)")"
  244. echo -n -e "$(pad_string "${icann_address}")"
  245. echo "${onion_address}"
  246. fi
  247. fi
  248. done
  249. if grep -q "rss reader domain" "$COMPLETION_FILE"; then
  250. if [ -d /var/lib/tor/hidden_service_ttrss ]; then
  251. echo -n -e "$(pad_string 'RSS reader')"
  252. RSSDOM='-'
  253. echo -n -e "$(pad_string ${RSSDOM})"
  254. echo -n "$(cat /var/lib/tor/hidden_service_ttrss/hostname)"
  255. echo ''
  256. fi
  257. if [ -d /var/lib/tor/hidden_service_mobilerss ]; then
  258. echo -n -e "$(pad_string 'RSS mobile')"
  259. RSSMOBILEDOM='-'
  260. echo -n -e "$(pad_string ${RSSMOBILEDOM})"
  261. echo -n "$(cat /var/lib/tor/hidden_service_mobilerss/hostname)"
  262. echo ''
  263. fi
  264. fi
  265. echo ''
  266. }
  267. function show_users {
  268. echo 'Users'
  269. echo '====='
  270. echo ''
  271. echo -n -e "$(pad_string 'Name')"
  272. echo -n -e "$(pad_string 'Data')"
  273. echo ''
  274. echo '----------------------------------'
  275. for d in /home/*/ ; do
  276. USRNAME=$(echo "$d" | awk -F '/' '{print $3}')
  277. if [[ $(is_valid_user "$USRNAME") == "1" ]]; then
  278. echo -n -e "$(pad_string "${USRNAME}")"
  279. # size of the home directory
  280. du -s -h "/home/${USRNAME}" | awk -F ' ' '{print $1}'
  281. fi
  282. done
  283. echo ''
  284. }
  285. function show_tahoelafs {
  286. if [ ! -f /home/tahoelafs/storage/private/storage.furl ]; then
  287. return
  288. fi
  289. echo 'Tahoe-LAFS Storage Node'
  290. echo '======================='
  291. echo ''
  292. echo "Hostname: $(get_tahoelafs_storage_hostname)"
  293. echo "Public key: $(get_tahoelafs_public_key)"
  294. echo "Nickname: $(get_tahoelafs_nick)"
  295. echo "FURL: $(get_tahoelafs_furl)"
  296. echo ''
  297. }
  298. function show_ip_addresses {
  299. echo $'IP/DNS addresses'
  300. echo '================'
  301. echo ''
  302. echo -n "IPv4: $(get_ipv4_address)/$(get_external_ipv4_address)"
  303. ipv6_address="$(get_ipv6_address)"
  304. if [ ${#ipv6_address} -gt 0 ]; then
  305. echo " IPv6: ${ipv6_address}"
  306. fi
  307. echo ''
  308. echo ''
  309. }
  310. function show_tor_bridges {
  311. bridges_list=$(grep "Bridge " /etc/tor/torrc | grep -v '##')
  312. if [ ${#bridges_list} -gt 0 ]; then
  313. echo $'Tor Bridges'
  314. echo '==========='
  315. echo ''
  316. echo "${bridges_list}"
  317. echo ''
  318. echo ''
  319. fi
  320. if ! grep -q "#BridgeRelay" /etc/tor/torrc; then
  321. if grep -q "BridgeRelay 1" /etc/tor/torrc; then
  322. read_config_param 'TOR_BRIDGE_PORT'
  323. read_config_param 'TOR_BRIDGE_NICKNAME'
  324. if [ ${#TOR_BRIDGE_NICKNAME} -gt 0 ]; then
  325. echo "Tor bridge on this system"
  326. echo '========================='
  327. echo ''
  328. echo "IP Address: $(get_ipv4_address)"
  329. echo "Port: ${TOR_BRIDGE_PORT}"
  330. echo "Nickname: ${TOR_BRIDGE_NICKNAME}"
  331. echo ''
  332. echo ''
  333. fi
  334. fi
  335. fi
  336. }
  337. function show_ssh_public_key {
  338. echo $'SSH Public Keys'
  339. echo '==============='
  340. echo ''
  341. get_ssh_server_key
  342. echo ''
  343. echo ''
  344. }
  345. function show_tahoelafs_introducer {
  346. INTRODUCER_FILENAME=/home/tahoelafs/data/private/introducer.furl
  347. if [ ! -f $INTRODUCER_FILENAME ]; then
  348. return
  349. fi
  350. echo $'Tahoe-LAFS introducer'
  351. echo '====================='
  352. echo ''
  353. cat $INTRODUCER_FILENAME
  354. echo ''
  355. echo ''
  356. }
  357. function show_about {
  358. detect_apps
  359. get_apps_installed_names
  360. clear
  361. echo "==== ${PROJECT_NAME} version ${VERSION} ($DEBIAN_VERSION) ===="
  362. echo ''
  363. show_ip_addresses
  364. show_tor_bridges
  365. show_ssh_public_key
  366. show_domains
  367. show_tahoelafs
  368. show_users
  369. any_key
  370. }
  371. function select_user {
  372. SELECTED_USERNAME=
  373. # shellcheck disable=SC2207
  374. users_array=($(ls /home))
  375. delete=(git)
  376. # shellcheck disable=SC2068
  377. for del in ${delete[@]}
  378. do
  379. # shellcheck disable=SC2206
  380. users_array=(${users_array[@]/$del})
  381. done
  382. i=0
  383. W=()
  384. name=()
  385. # shellcheck disable=SC2068
  386. for u in ${users_array[@]}
  387. do
  388. if [[ $(is_valid_user "$u") == "1" ]]; then
  389. i=$((i+1))
  390. W+=("$i" "$u")
  391. name+=("$u")
  392. fi
  393. done
  394. if [ $i -eq 1 ]; then
  395. SELECTED_USERNAME="${name[0]}"
  396. else
  397. # shellcheck disable=SC2068
  398. user_index=$(dialog --backtitle $"Freedombone Control Panel" --title $"Select User" --menu $"Select one of the following:" 24 40 17 ${W[@]} 3>&2 2>&1 1>&3)
  399. # shellcheck disable=SC2181
  400. if [ $? -eq 0 ]; then
  401. SELECTED_USERNAME="${name[$((user_index-1))]}"
  402. fi
  403. fi
  404. }
  405. function delete_user {
  406. select_user
  407. if [ ! "$SELECTED_USERNAME" ]; then
  408. return
  409. fi
  410. if grep -Fxq "Admin user:$SELECTED_USERNAME" "$COMPLETION_FILE"; then
  411. dialog --title $"Administrator user" \
  412. --msgbox $"You can't delete the administrator user" 6 40
  413. return
  414. fi
  415. clear
  416. "${PROJECT_NAME}-rmuser" "$SELECTED_USERNAME"
  417. any_key
  418. }
  419. function configure_remote_backups {
  420. if ! grep -Fxq "Admin user:$ADMIN_USER" "$COMPLETION_FILE"; then
  421. dialog --title $"Administrator user" \
  422. --msgbox $"No Administrator user found. Check $COMPLETION_FILE" 6 40
  423. return
  424. fi
  425. if [ ${#ADMIN_USER} -lt 2 ]; then
  426. dialog --title $"Administrator user" \
  427. --msgbox $"Username not found" 6 40
  428. return
  429. fi
  430. if [ ! -d "/home/$ADMIN_USER" ]; then
  431. dialog --title $"Administrator user" \
  432. --msgbox $"Home directory not found" 6 40
  433. return
  434. fi
  435. if ! "${PROJECT_NAME}-remote" -u "$ADMIN_USER"; then
  436. any_key
  437. fi
  438. }
  439. function change_password {
  440. select_user
  441. if [ ! "$SELECTED_USERNAME" ]; then
  442. return
  443. fi
  444. dialog --title $"Change password" \
  445. --passwordbox $"New password for user $SELECTED_USERNAME" 8 40 2> "$data"
  446. newpassword=$(<"$data")
  447. rm -f "$data"
  448. if [ "${#newpassword}" -lt "${MINIMUM_PASSWORD_LENGTH}" ]; then
  449. dialog --title $"Change password" \
  450. --msgbox $"The password should be ${MINIMUM_PASSWORD_LENGTH} or more characters" 6 40
  451. return
  452. fi
  453. echo "$SELECTED_USERNAME:$newpassword"|chpasswd
  454. dialog --title $"Change password" \
  455. --msgbox $"Password for $SELECTED_USERNAME was changed" 6 40
  456. }
  457. function change_ssh_public_key {
  458. select_user
  459. if [ ! "$SELECTED_USERNAME" ]; then
  460. return
  461. fi
  462. if grep -Fxq "Admin user:$SELECTED_USERNAME" "$COMPLETION_FILE"; then
  463. dialog --title $"Change ssh public key" \
  464. --backtitle $"Freedombone Control Panel" \
  465. --defaultno \
  466. --yesno $"\\nThis is the administrator user.\\n\\nAre you sure you want to change the ssh public key for the administrator?" 10 60
  467. sel=$?
  468. case $sel in
  469. 1) return;;
  470. 255) return;;
  471. esac
  472. fi
  473. data=$(mktemp 2>/dev/null)
  474. dialog --title $"Change ssh public key for $SELECTED_USERNAME" \
  475. --backtitle $"Freedombone Control Panel" \
  476. --inputbox $"Paste the ssh public key below" 8 60 2>"$data"
  477. sel=$?
  478. case $sel in
  479. 0)
  480. SSH_PUBLIC_KEY=$(<"$data")
  481. if [ "$SSH_PUBLIC_KEY" ]; then
  482. if [ ${#SSH_PUBLIC_KEY} -gt 5 ]; then
  483. if [ -f "$SSH_PUBLIC_KEY" ]; then
  484. if [ ! -d "/home/$SELECTED_USERNAME/.ssh" ]; then
  485. mkdir "/home/$SELECTED_USERNAME/.ssh"
  486. fi
  487. cp "$SSH_PUBLIC_KEY" \
  488. "/home/$SELECTED_USERNAME/.ssh/authorized_keys"
  489. chown -R "$SELECTED_USERNAME":"$SELECTED_USERNAME" \
  490. "/home/$SELECTED_USERNAME/.ssh"
  491. dialog --title $"Change ssh public key" \
  492. --msgbox $"ssh public key was installed" 6 40
  493. else
  494. if [[ "$SSH_PUBLIC_KEY" == "ssh-"* ]]; then
  495. if [ ! -d "/home/$SELECTED_USERNAME/.ssh" ]; then
  496. mkdir "/home/$SELECTED_USERNAME/.ssh"
  497. fi
  498. echo "$SSH_PUBLIC_KEY" > \
  499. "/home/$SELECTED_USERNAME/.ssh/authorized_keys"
  500. chown -R "$SELECTED_USERNAME":"$SELECTED_USERNAME" \
  501. "/home/$SELECTED_USERNAME/.ssh"
  502. dialog --title $"Change ssh public key" \
  503. --msgbox $"ssh public key was installed" 6 40
  504. fi
  505. fi
  506. fi
  507. fi
  508. ;;
  509. esac
  510. rm -f "$data"
  511. }
  512. function remove_user_from_mailing_list {
  513. select_user
  514. if [ ! "$SELECTED_USERNAME" ]; then
  515. return
  516. fi
  517. USER_MAILING_LISTS=$(grep '\[' "/home/$SELECTED_USERNAME/.procmailrc" | grep '\]' | awk -F '\[' '{print $2}' | awk -F '\\' '{print $1}')
  518. i=0
  519. W=()
  520. list_name=()
  521. while read -r listname; do
  522. i=$((i+1))
  523. W+=("$i" "$listname")
  524. list_name+=("$listname")
  525. echo "$listname"
  526. done <<< "$USER_MAILING_LISTS"
  527. i=$((i+1))
  528. W+=("$i" $"Exit back to user mainenance")
  529. # shellcheck disable=SC2068
  530. list_selected=$(dialog --default-item "$i" --backtitle $"Freedombone Control Panel" --title $"Remove a mailing list for $SELECTED_USERNAME" --menu $"Select one of the following:" 24 50 17 ${W[@]} 3>&2 2>&1 1>&3)
  531. # shellcheck disable=SC2181
  532. if [ $? -eq 0 ]; then # Exit with OK
  533. if [ "${list_selected}" -ne "${i}" ]; then
  534. remove_list_name="${list_name[$((list_selected-1))]}"
  535. # find the line number where the list is defined
  536. line_number=0
  537. i=0
  538. while read -r line
  539. do
  540. if [[ "$line" == *"\\[${remove_list_name}\\]"* ]]; then
  541. line_number=${i}
  542. fi
  543. i=$((i+1))
  544. done < "/home/$SELECTED_USERNAME/.procmailrc"
  545. if [ ${line_number} -eq 0 ]; then
  546. # no match was found
  547. return
  548. fi
  549. # recreate the file
  550. if [ -f "/home/${SELECTED_USERNAME}/.procmailrc_new" ]; then
  551. rm "/home/${SELECTED_USERNAME}/.procmailrc_new"
  552. fi
  553. i=0
  554. clip=0
  555. while read -r line
  556. do
  557. i=$((i+1))
  558. if [ ${i} -gt $((line_number-1)) ]; then
  559. if [ ${clip} -eq 0 ]; then
  560. clip=1
  561. fi
  562. if [ ${clip} -eq 1 ]; then
  563. if [ ${i} -lt $((line_number+2)) ]; then
  564. continue
  565. else
  566. if [ ${#line} -lt 1 ]; then
  567. clip=2
  568. continue
  569. fi
  570. if [[ "$line" == ":"* || "$line" == "#"* ]]; then
  571. clip=2
  572. else
  573. continue
  574. fi
  575. fi
  576. fi
  577. fi
  578. echo "$line" >> "/home/${SELECTED_USERNAME}/.procmailrc_new"
  579. if [[ "$line" == *"\\[${remove_list_name}\\]"* ]]; then
  580. line_number=${i}
  581. fi
  582. done < "/home/$SELECTED_USERNAME/.procmailrc"
  583. cp "/home/${SELECTED_USERNAME}/.procmailrc_new" "/home/${SELECTED_USERNAME}/.procmailrc"
  584. rm "/home/${SELECTED_USERNAME}/.procmailrc_new"
  585. chown "${SELECTED_USERNAME}":"${SELECTED_USERNAME}" "/home/${SELECTED_USERNAME}/.procmailrc"
  586. dialog --title $"Remove user from mailing list" \
  587. --msgbox $"${SELECTED_USERNAME} has been removed from ${remove_list_name}" 6 50
  588. fi
  589. fi
  590. }
  591. function add_to_mailing_list {
  592. select_user
  593. if [ ! "$SELECTED_USERNAME" ]; then
  594. return
  595. fi
  596. data=$(mktemp 2>/dev/null)
  597. dialog --backtitle $"Freedombone Control Panel" \
  598. --title $"Subscribe $SELECTED_USERNAME to a mailing list" \
  599. --form $"You can either enter a subject or an email address\\n" 11 68 4 \
  600. $"List folder name:" 1 1 "" 1 35 26 25 \
  601. $"Name between [] on subject line:" 2 1 "" 2 35 26 25 \
  602. $"List email address:" 3 1 "" 3 35 26 25 \
  603. $"Public:" 4 1 $"yes" 4 35 4 25 \
  604. 2> "$data"
  605. sel=$?
  606. case $sel in
  607. 1) rm -f "$data"
  608. return;;
  609. 255) rm -f "$data"
  610. return;;
  611. esac
  612. LIST_NAME=$(sed -n 1p < "$data")
  613. LIST_SUBJECT=$(sed -n 2p < "$data")
  614. LIST_EMAIL=$(sed -n 3p < "$data")
  615. LIST_PUBLIC=$(sed -n 4p < "$data")
  616. if [ ${#LIST_PUBLIC} -lt 1 ]; then
  617. LIST_PUBLIC='no'
  618. fi
  619. if [[ $LIST_PUBLIC == $'y' || $LIST_PUBLIC == $'Y' || $LIST_PUBLIC == $'true' || $LIST_PUBLIC == $'True' || $LIST_PUBLIC == $'yes' || $LIST_PUBLIC == $'Yes' || $LIST_PUBLIC == $'YES' ]]; then
  620. LIST_PUBLIC='yes'
  621. else
  622. LIST_PUBLIC='no'
  623. fi
  624. if [ ${#LIST_NAME} -lt 2 ]; then
  625. dialog --title $"Add mailing list" \
  626. --msgbox $"No mailing list name was given" 6 40
  627. rm -f "$data"
  628. return
  629. fi
  630. if [ ${#LIST_SUBJECT} -lt 2 ]; then
  631. if [ ${#LIST_EMAIL} -lt 2 ]; then
  632. dialog --title $"Add mailing list" \
  633. --msgbox $"No mailing list subject or address was given" 6 40
  634. rm -f "$data"
  635. return
  636. fi
  637. fi
  638. if [ ${#LIST_SUBJECT} -gt 1 ]; then
  639. "${PROJECT_NAME}-addlist" -u "$SELECTED_USERNAME" -l "$LIST_NAME" \
  640. -s "$LIST_SUBJECT" --public "$LIST_PUBLIC"
  641. else
  642. if [[ "$LIST_EMAIL" != *"@"* || "$LIST_EMAIL" != *"."* ]]; then
  643. dialog --title $"Add mailing list" \
  644. --msgbox $"Unrecognised email address" 6 40
  645. rm -f "$data"
  646. return
  647. else
  648. "${PROJECT_NAME}-addlist" -u "$SELECTED_USERNAME" -l "$LIST_NAME" \
  649. -e "$LIST_EMAIL" --public "$LIST_PUBLIC"
  650. fi
  651. fi
  652. dialog --title $"Add mailing list" \
  653. --msgbox $"$LIST_NAME list was added" 6 40
  654. rm -f "$data"
  655. }
  656. function email_rule {
  657. select_user
  658. if [ ! "$SELECTED_USERNAME" ]; then
  659. return
  660. fi
  661. data=$(mktemp 2>/dev/null)
  662. dialog --backtitle $"Freedombone Control Panel" \
  663. --title $"Email rule for user $SELECTED_USERNAME" \
  664. --form "\\n" 9 65 4 \
  665. $"When email arrives from address:" 1 1 "" 1 35 24 28 \
  666. $"Move to folder:" 2 1 "" 2 35 24 28 \
  667. $"Public:" 3 1 $"no" 3 35 4 25 \
  668. 2> "$data"
  669. sel=$?
  670. case $sel in
  671. 1) rm -f "$data"
  672. return;;
  673. 255) rm -f "$data"
  674. return;;
  675. esac
  676. RULE_EMAIL=$(sed -n 1p < "$data")
  677. RULE_FOLDER=$(sed -n 2p < "$data")
  678. RULE_PUBLIC=$(sed -n 3p < "$data")
  679. if [ ${#RULE_PUBLIC} -lt 1 ]; then
  680. RULE_PUBLIC='no'
  681. fi
  682. if [[ $RULE_PUBLIC == $'y' || $RULE_PUBLIC == $'Y' || $RULE_PUBLIC == $'true' || $RULE_PUBLIC == $'True' || $RULE_PUBLIC == $'yes' || $RULE_PUBLIC == $'Yes' || $RULE_PUBLIC == $'YES' ]]; then
  683. RULE_PUBLIC='yes'
  684. else
  685. RULE_PUBLIC='no'
  686. fi
  687. if [ ${#RULE_EMAIL} -lt 2 ]; then
  688. dialog --title $"Add email rule" \
  689. --msgbox $"No email address was given" 6 40
  690. rm -f "$data"
  691. return
  692. fi
  693. if [ ${#RULE_FOLDER} -lt 2 ]; then
  694. dialog --title $"Add email rule" \
  695. --msgbox $"No folder name was given" 6 40
  696. rm -f "$data"
  697. return
  698. fi
  699. if [[ "$RULE_EMAIL" != *"@"* || "$RULE_EMAIL" != *"."* ]]; then
  700. dialog --title $"Add email rule" \
  701. --msgbox $"Unrecognised email address" 6 40
  702. rm -f "$data"
  703. return
  704. fi
  705. "${PROJECT_NAME}-addemail" -u "$SELECTED_USERNAME" -e "$RULE_EMAIL" \
  706. -g "$RULE_FOLDER" --public $RULE_PUBLIC
  707. dialog --title $"Add email rule" \
  708. --msgbox $"Email rule for $RULE_EMAIL was added" 6 40
  709. rm -f "$data"
  710. }
  711. function block_unblock_email {
  712. select_user
  713. if [ ! "$SELECTED_USERNAME" ]; then
  714. return
  715. fi
  716. blockstr=$"Block/Unblock email going to"
  717. data=$(mktemp 2>/dev/null)
  718. dialog --backtitle $"Freedombone Control Panel" \
  719. --title "$blockstr $SELECTED_USERNAME" \
  720. --form "\\n" 8 65 3 \
  721. $"When email arrives from address:" 1 1 "" 1 35 24 100 \
  722. $"Block it:" 2 1 "yes" 2 35 4 4 \
  723. 2> "$data"
  724. sel=$?
  725. case $sel in
  726. 1) rm -f "$data"
  727. return;;
  728. 255) rm -f "$data"
  729. return;;
  730. esac
  731. BLOCK_EMAIL=$(sed -n 1p < "$data")
  732. BLOCK=$(sed -n 2p < "$data")
  733. rm -f "$data"
  734. if [ ${#BLOCK_EMAIL} -lt 2 ]; then
  735. dialog --title $"Block/Unblock an email" \
  736. --msgbox $"No email address was given" 6 40
  737. return
  738. fi
  739. if [[ "$BLOCK_EMAIL" != *"@"* || "$BLOCK_EMAIL" != *"."* ]]; then
  740. dialog --title $"Block/Unblock an email" \
  741. --msgbox $"Unrecognised email address" 6 40
  742. return
  743. fi
  744. if [[ $BLOCK == "y"* || $BLOCK == "Y"* ]]; then
  745. "${PROJECT_NAME}-ignore" -u "$SELECTED_USERNAME" -e "$BLOCK_EMAIL"
  746. dialog --title $"Block an email" \
  747. --msgbox "Email from $BLOCK_EMAIL to $SELECTED_USERNAME blocked" 6 75
  748. else
  749. "${PROJECT_NAME}-unignore" -u "$SELECTED_USERNAME" -e "$BLOCK_EMAIL"
  750. dialog --title $"Unblock an email" \
  751. --msgbox "Email from $BLOCK_EMAIL to $SELECTED_USERNAME unblocked" 6 75
  752. fi
  753. }
  754. function block_unblock_subject {
  755. select_user
  756. if [ ! "$SELECTED_USERNAME" ]; then
  757. return
  758. fi
  759. blockstr=$"Block/Unblock email going to"
  760. data=$(mktemp 2>/dev/null)
  761. dialog --backtitle $"Freedombone Control Panel" \
  762. --title "$blockstr $SELECTED_USERNAME" \
  763. --form "\\n" 8 70 3 \
  764. $"When email arrives with subject text:" 1 1 "" 1 40 24 28 \
  765. $"Block it:" 2 1 "yes" 2 40 4 4 \
  766. 2> "$data"
  767. sel=$?
  768. case $sel in
  769. 1) rm -f "$data"
  770. return;;
  771. 255) rm -f "$data"
  772. return;;
  773. esac
  774. BLOCK_SUBJECT=$(sed -n 1p < "$data")
  775. BLOCK=$(sed -n 2p < "$data")
  776. rm -f "$data"
  777. if [ ${#BLOCK_SUBJECT} -lt 2 ]; then
  778. dialog --title $"Block/Unblock an email" \
  779. --msgbox $"No subject was given" 6 40
  780. return
  781. fi
  782. if [[ $BLOCK == "y"* || $BLOCK == "Y"* ]]; then
  783. "${PROJECT_NAME}-ignore" -u "$SELECTED_USERNAME" -t "$BLOCK_SUBJECT"
  784. dialog --title $"Block an email" \
  785. --msgbox "Email with subject $BLOCK_SUBJECT to $SELECTED_USERNAME blocked" 6 40
  786. else
  787. "${PROJECT_NAME}-unignore" -u "$SELECTED_USERNAME" -t "$BLOCK_SUBJECT"
  788. dialog --title $"Unblock an email" \
  789. --msgbox "Email with subject $BLOCK_SUBJECT to $SELECTED_USERNAME unblocked" 6 40
  790. fi
  791. }
  792. function create_keydrive_master {
  793. select_user
  794. if [ ! "$SELECTED_USERNAME" ]; then
  795. return
  796. fi
  797. dialog --title $"USB Master Keydrive" \
  798. --msgbox $"Plug in a LUKS encrypted USB drive" 6 40
  799. clear
  800. detect_usb_drive
  801. "${PROJECT_NAME}-keydrive" -u "$SELECTED_USERNAME" --master 'yes' -d "$USB_DRIVE"
  802. any_key
  803. }
  804. function create_keydrive_fragment {
  805. select_user
  806. if [ ! "$SELECTED_USERNAME" ]; then
  807. return
  808. fi
  809. dialog --title $"USB Fragment Keydrive" \
  810. --msgbox $"Plug in a LUKS encrypted USB drive" 6 40
  811. clear
  812. detect_usb_drive
  813. "${PROJECT_NAME}-keydrive" -u "$SELECTED_USERNAME" -d "$USB_DRIVE"
  814. any_key
  815. }
  816. function backup_data {
  817. dialog --title $"Backup data to USB" \
  818. --msgbox $"Plug in a LUKS encrypted USB drive" 6 40
  819. clear
  820. detect_usb_drive
  821. echo ''
  822. echo $"Detected USB drive $USB_DRIVE"
  823. echo ''
  824. echo $'Enter the passphrase for your LUKS encrypted backup drive:'
  825. "${PROJECT_NAME}-backup-local"
  826. any_key
  827. }
  828. function restore_data_from_storage {
  829. restore_type="$1"
  830. AllStr=$"all"
  831. ExitStr=$"Exit"
  832. RestoreStr=$"Restore apps"
  833. if [[ $restore_type != "local" ]]; then
  834. restore_command="${PROJECT_NAME}-restore-remote $remote_domain_name configuration;;"
  835. else
  836. remote_domain_name="$1"
  837. detect_usb_drive
  838. restore_command="${PROJECT_NAME}-restore-local $USB_DRIVE"
  839. RestoreStr=$"Restore apps from USB drive $USB_DRIVE"
  840. fi
  841. utils_installed=(configfiles
  842. blocklist
  843. mariadb
  844. postgresql
  845. letsencrypt
  846. passwords
  847. mutt
  848. gpg
  849. procmail
  850. spamassassin
  851. readme
  852. ssh
  853. userconfig
  854. userlocal
  855. userfin
  856. certs
  857. personal
  858. email)
  859. detect_apps
  860. while true
  861. do
  862. app_list=()
  863. n=1
  864. applist="$n $AllStr off"
  865. n=$((n+1))
  866. app_list+=("$AllStr")
  867. util_index=0
  868. # shellcheck disable=SC2068
  869. for a in ${utils_installed[@]}
  870. do
  871. applist="$applist $n $a off"
  872. app_name=${utils_installed[util_index]}
  873. n=$((n+1))
  874. util_index=$((util_index+1))
  875. app_list+=("$app_name")
  876. done
  877. app_index=0
  878. # shellcheck disable=SC2068
  879. for a in ${APPS_INSTALLED_NAMES[@]}
  880. do
  881. applist="$applist $n $a off"
  882. n=$((n+1))
  883. app_name=${APPS_INSTALLED_NAMES[app_index]}
  884. app_index=$((app_index+1))
  885. app_list+=("$app_name")
  886. done
  887. applist="$applist $n $ExitStr on"
  888. n=$((n+1))
  889. app_list+=("$ExitStr")
  890. # shellcheck disable=SC2086
  891. choice=$(dialog --stdout --backtitle $"Freedombone" \
  892. --title "$RestoreStr" \
  893. --radiolist $'Choose:' \
  894. 30 50 20 $applist)
  895. # shellcheck disable=SC2181
  896. if [ $? -ne 0 ]; then
  897. break
  898. fi
  899. app_index=$((choice-1))
  900. app_name=${app_list[app_index]}
  901. # exit
  902. if [[ "$app_name" == "$ExitStr" ]]; then
  903. break
  904. fi
  905. clear
  906. # Restore all
  907. if [[ "$app_name" == "$AllStr" ]]; then
  908. $restore_command
  909. retcode="$?"
  910. if [[ "$retcode" != "0" ]]; then
  911. any_key
  912. if [[ "$1" == "local" ]]; then
  913. dialog --title $"Restore all apps from USB" \
  914. --msgbox $"Restore failed with code $retcode" 6 60
  915. else
  916. dialog --title $"Restore all apps from $1" \
  917. --msgbox $"Restore failed with code $retcode" 6 60
  918. fi
  919. break
  920. fi
  921. if [[ "$1" == "local" ]]; then
  922. dialog --title $"Restore all apps from USB" \
  923. --msgbox $"Restore complete" 6 40
  924. else
  925. dialog --title $"Restore all apps from $1" \
  926. --msgbox $"Restore complete" 6 40
  927. fi
  928. break
  929. fi
  930. # Restore an app
  931. $restore_command "${app_name}"
  932. retcode="$?"
  933. if [[ "$retcode" != "0" ]]; then
  934. any_key
  935. dialog --title $"Restore apps from USB" \
  936. --msgbox $"Restore of ${app_name} failed with code $retcode" 6 60
  937. return
  938. fi
  939. # finished
  940. if [[ "$1" == "local" ]]; then
  941. dialog --title $"Restore apps from USB" \
  942. --msgbox $"Restore complete" 6 40
  943. else
  944. dialog --title $"Restore apps from $1" \
  945. --msgbox $"Restore complete" 6 40
  946. fi
  947. done
  948. }
  949. function restore_data {
  950. dialog --title $"Restore data from USB" \
  951. --msgbox $"Plug in your backup USB drive" 6 40
  952. clear
  953. echo ' '
  954. echo $'Enter the passphrase for your LUKS encrypted backup drive:'
  955. restore_data_from_storage local
  956. }
  957. function restore_data_remote {
  958. if [ ! $ADMIN_USER ]; then
  959. dialog --title $"Restore data from remote server" \
  960. --msgbox $"Unknown admin user" 6 40
  961. return
  962. fi
  963. data=$(mktemp 2>/dev/null)
  964. dialog --title $"Restore from remote server" \
  965. --backtitle $"Freedombone Control Panel" \
  966. --inputbox $"Enter the domain name of the server from which you wish to restore" 8 60 2>"$data"
  967. sel=$?
  968. case $sel in
  969. 0)
  970. friend_server_domain_name=$(<"$data")
  971. if [ ${#friend_server_domain_name} -lt 2 ]; then
  972. rm -f "$data"
  973. return
  974. fi
  975. if [[ $friend_server_domain_name != *"."* ]]; then
  976. dialog --title $"Remote server domain name" \
  977. --msgbox $"Invalid domain name" 6 40
  978. rm -f "$data"
  979. return
  980. fi
  981. restore_data_from_storage "$friend_server_domain_name"
  982. ;;
  983. esac
  984. rm -f "$data"
  985. }
  986. function ping_enable_disable {
  987. ping_str=$"\\nDo you want to enable other systems to ping this machine?\\n\\nPing may be useful for diagnostic purposes, but for added security you may not want to enable it."
  988. enable_ping="no"
  989. dialog --title $"Enable Ping / ICMP" \
  990. --backtitle $"Freedombone Control Panel" \
  991. --defaultno \
  992. --yesno "$ping_str" 10 60
  993. sel=$?
  994. case $sel in
  995. 0) enable_ping="yes";;
  996. 255) return;;
  997. esac
  998. if [[ $enable_ping == "yes" ]]; then
  999. iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
  1000. iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  1001. echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all
  1002. else
  1003. iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT
  1004. iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  1005. echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
  1006. fi
  1007. }
  1008. function logging_on_off {
  1009. logging="no"
  1010. dialog --title $"Logging" \
  1011. --backtitle $"Freedombone Control Panel" \
  1012. --defaultno \
  1013. --yesno $"\\nDo you want to turn logging on?" 7 60
  1014. sel=$?
  1015. case $sel in
  1016. 0) logging="yes";;
  1017. 255) return;;
  1018. esac
  1019. clear
  1020. echo ''
  1021. echo $'This may take a few seconds. Please wait...'
  1022. if [[ $logging == "no" ]]; then
  1023. ${PROJECT_NAME}-logging off
  1024. else
  1025. ${PROJECT_NAME}-logging on
  1026. fi
  1027. }
  1028. function restore_gpg_key {
  1029. select_user
  1030. if [ ! "$SELECTED_USERNAME" ]; then
  1031. return
  1032. fi
  1033. restorestr=$"Restore GPG key for user"
  1034. dialog --title "$restorestr $SELECTED_USERNAME" \
  1035. --msgbox $"Plug in your USB keydrive" 6 40
  1036. clear
  1037. "${PROJECT_NAME}-recoverkey" -u "$SELECTED_USERNAME"
  1038. any_key
  1039. }
  1040. function security_settings {
  1041. "${PROJECT_NAME}-sec"
  1042. }
  1043. function format_drive {
  1044. detect_usb_drive
  1045. dialog --title $"Format USB drive $USB_DRIVE" \
  1046. --backtitle $"Freedombone Control Panel" \
  1047. --defaultno \
  1048. --yesno $"\\nPlease confirm that you wish to format drive\\n\\n ${USB_DRIVE}\\n\\nAll current data on the drive will be lost, and you will be prompted to give a password used to encrypt the drive.\\n\\nDANGER: If you screw up here and format the wrong drive it's your own fault!" 16 60
  1049. sel=$?
  1050. case $sel in
  1051. 1) return;;
  1052. 255) return;;
  1053. esac
  1054. clear
  1055. echo ''
  1056. echo $"Formatting drive $USB_DRIVE. ALL CONTENTS WILL BE LOST."
  1057. echo ''
  1058. "${PROJECT_NAME}-format" "$USB_DRIVE"
  1059. any_key
  1060. }
  1061. function remove_backups {
  1062. detect_usb_drive
  1063. # shellcheck disable=SC2154
  1064. dialog --title $"Remove backups from a USB drive $USB_DRIVE" \
  1065. --backtitle $"Freedombone Control Panel" \
  1066. --defaultno \
  1067. --yesno $"\\nPlease confirm that you wish to remove backups from this drive\\n\\n ${drive}\\n\\nYou will not be able to recover them afterwards." 12 60
  1068. sel=$?
  1069. case $sel in
  1070. 1) return;;
  1071. 255) return;;
  1072. esac
  1073. clear
  1074. "${PROJECT_NAME}-backup-local" "$USB_DRIVE" remove
  1075. any_key
  1076. }
  1077. function shut_down_system {
  1078. dialog --title $"Power off the system" \
  1079. --backtitle $"Freedombone Control Panel" \
  1080. --defaultno \
  1081. --yesno $"\\nPlease confirm that you wish to power off the system.\\n\\nWARNING: to power on again you will need to have physical access to the hardware." 10 60
  1082. sel=$?
  1083. case $sel in
  1084. 1) return;;
  1085. 255) return;;
  1086. esac
  1087. systemctl poweroff
  1088. }
  1089. function restart_system {
  1090. dialog --title $"Restart the system" \
  1091. --backtitle $"Freedombone Control Panel" \
  1092. --defaultno \
  1093. --yesno $"\\nPlease confirm that you wish to restart the system.\\n\\nWARNING: If you are using full disk encryption then you will need physical access to the hardware to type in the password" 10 60
  1094. sel=$?
  1095. case $sel in
  1096. 1) return;;
  1097. 255) return;;
  1098. esac
  1099. systemctl reboot -i
  1100. }
  1101. function change_system_name {
  1102. data=$(mktemp 2>/dev/null)
  1103. dialog --title $"Change the name of this system" \
  1104. --backtitle $"Freedombone Control Panel" \
  1105. --inputbox $'Enter a new name for this system on your local network\\n\\nIt will appear as newname.local' 10 60 2>"$data"
  1106. sel=$?
  1107. case $sel in
  1108. 0) NEW_SYSTEM_NAME=$(<"$data")
  1109. if [ "$NEW_SYSTEM_NAME" ]; then
  1110. if [ ${#NEW_SYSTEM_NAME} -gt 1 ]; then
  1111. sed -i "s|host-name=.*|host-name=$NEW_SYSTEM_NAME|g" /etc/avahi/avahi-daemon.conf
  1112. systemctl restart avahi-daemon
  1113. if grep -q "host-name=$NEW_SYSTEM_NAME" /etc/avahi/avahi-daemon.conf; then
  1114. dialog --title $"New local network name" \
  1115. --msgbox $"The name of this system on your local network was changed successfully" 6 70
  1116. fi
  1117. fi
  1118. fi
  1119. ;;
  1120. esac
  1121. rm -f "$data"
  1122. }
  1123. function set_dynamic_IP {
  1124. revert_to_dynamic=
  1125. dialog --title $"Return to using a dynamic IP address" \
  1126. --backtitle $"Freedombone Control Panel" \
  1127. --yesno $"\\nDo you wish to go back to using a dynamic IP address?" 8 60
  1128. sel=$?
  1129. case $sel in
  1130. 0) revert_to_dynamic=1
  1131. ;;
  1132. 1) return;;
  1133. esac
  1134. if [ $revert_to_dynamic ]; then
  1135. wifi_original_network_settings
  1136. clear
  1137. echo ''
  1138. echo $'Changing to a dynamic IP address.'
  1139. echo ''
  1140. echo $"System is rebooting. You may need to close this terminal and log in from a new one."
  1141. systemctl reboot -i
  1142. fi
  1143. }
  1144. function set_static_IP {
  1145. IPv4_address=$(get_ipv4_address)
  1146. IPv4_address_base=$(echo "$IPv4_address" | awk -F '.' '{print $1"."$2"."$3}')
  1147. STATIC_IP="${IPv4_address_base}.60"
  1148. STATIC_GATEWAY="${IPv4_address_base}.1"
  1149. NEW_STATIC_IP=
  1150. NEW_STATIC_GATEWAY=
  1151. if [ -f /etc/network/interfaces.d/static ]; then
  1152. STATIC_IP=$(grep "address " /etc/network/interfaces.d/static | head -n 1 | awk -F ' ' '{print $2}')
  1153. STATIC_GATEWAY=$(grep "gateway " /etc/network/interfaces.d/static | head -n 1 | awk -F ' ' '{print $2}')
  1154. fi
  1155. # get the IP for the box
  1156. data=$(mktemp 2>/dev/null)
  1157. dialog --title $"Set a static local IP address" \
  1158. --backtitle $"Freedombone Control Panel" \
  1159. --inputbox $"In order to forward incoming internet traffic to this system most internet routers need to know a static local IP address to send the data to.\\n\\n
  1160. Enter a static local IP address for this system.\\n\\nIt will typically be ${IPv4_address_base}.x\\n\\nIf you leave this field blank then the system will revert to using a dynamic IP address." 18 60 "$STATIC_IP" 2>"$data"
  1161. sel=$?
  1162. case $sel in
  1163. 0) NEW_STATIC_IP=$(<"$data")
  1164. if [[ "$NEW_STATIC_IP" != *"."* ]]; then
  1165. set_dynamic_IP
  1166. rm -f "$data"
  1167. return
  1168. fi
  1169. ;;
  1170. 1) rm -f "$data"
  1171. return;;
  1172. esac
  1173. rm -f "$data"
  1174. # get the gateway
  1175. data=$(mktemp 2>/dev/null)
  1176. dialog --title $"Set the IP address of your internet router/modem" \
  1177. --backtitle $"Freedombone Control Panel" \
  1178. --inputbox $"Set the local IP address for your internet router or ADSL modem.\\n\\nIt will typically be ${IPv4_address_base}.1, ${IPv4_address_base}.254, or similar" 12 60 "$STATIC_GATEWAY" 2>"$data"
  1179. sel=$?
  1180. case $sel in
  1181. 0) NEW_STATIC_GATEWAY=$(<"$data")
  1182. if [[ "$NEW_STATIC_GATEWAY" != *"."* ]]; then
  1183. rm -f "$data"
  1184. return
  1185. fi
  1186. ;;
  1187. 1) rm -f "$data"
  1188. return;;
  1189. esac
  1190. if [[ "$NEW_STATIC_GATEWAY" == *"."* && "$NEW_STATIC_IP" == *"."* ]]; then
  1191. ip_addresses_have_changed=1
  1192. if [ -f /etc/network/interfaces.d/static ]; then
  1193. ip_addresses_have_changed=
  1194. if ! grep -q "address ${NEW_STATIC_IP}" /etc/network/interfaces.d/static; then
  1195. ip_addresses_have_changed=1
  1196. fi
  1197. if ! grep -q "gateway ${NEW_STATIC_GATEWAY}" /etc/network/interfaces.d/static; then
  1198. ip_addresses_have_changed=1
  1199. fi
  1200. fi
  1201. if [ $ip_addresses_have_changed ]; then
  1202. write_config_param "NETWORK_IS_STATIC" "1"
  1203. write_config_param "LOCAL_NETWORK_STATIC_IP_ADDRESS" "$NEW_STATIC_IP"
  1204. write_config_param "ROUTER_IP_ADDRESS" "$NEW_STATIC_GATEWAY"
  1205. email_change_relay "$NEW_STATIC_IP"
  1206. static_wifi_address=
  1207. if [[ $(config_param_exists "WIFI_INTERFACE") == "1" ]]; then
  1208. dialog --title $"Static local IP address" \
  1209. --backtitle $"Freedombone Control Panel" \
  1210. --yesno $"\\nSet a static address for the wifi adapter?\\n\\nIf you select 'no' then wired ethernet will be used." 10 60
  1211. sel=$?
  1212. case $sel in
  1213. 0) static_wifi_address=1
  1214. write_config_param "NETWORK_IS_STATIC" "1"
  1215. ;;
  1216. esac
  1217. fi
  1218. echo '# This file describes the network interfaces available on your system' > /etc/network/interfaces
  1219. echo '# and how to activate them. For more information, see interfaces(5).' >> /etc/network/interfaces
  1220. echo 'source /etc/network/interfaces.d/*' >> /etc/network/interfaces
  1221. if [ ! $static_wifi_address ]; then
  1222. # wired network
  1223. remove_wifi_startup_script
  1224. { echo 'auto eth0';
  1225. echo 'iface eth0 inet static';
  1226. echo " address ${NEW_STATIC_IP}";
  1227. echo ' netmask 255.255.255.0';
  1228. echo " gateway ${NEW_STATIC_GATEWAY}"; } >> /etc/network/interfaces.d/static
  1229. else
  1230. # wifi network
  1231. wifi_settings
  1232. fi
  1233. clear
  1234. echo ''
  1235. echo $'Restarting the network daemon.'
  1236. echo ''
  1237. echo $'If you logged in using the previous IP address then you may need to close this terminal and log in again on the new one.'
  1238. function_check pihole_change_ipv4
  1239. pihole_change_ipv4 "${NEW_STATIC_IP}"
  1240. dialog --title $"Static local IP address" \
  1241. --backtitle $"Freedombone Control Panel" \
  1242. --yesno $"\\nFor the change to take effect your system will now need to reboot. Do this now?" 8 60
  1243. sel=$?
  1244. case $sel in
  1245. 0) systemctl reboot -i;;
  1246. esac
  1247. fi
  1248. fi
  1249. rm -f "$data"
  1250. }
  1251. function wifi_settings {
  1252. if [ -f /etc/hostapd/hostapd.conf ]; then
  1253. return
  1254. fi
  1255. TEMP_WIFI_NETWORKS_FILE=~/.temp-${PROJECT_NAME}-wifi.cfg
  1256. ${PROJECT_NAME}-wifi --networksinteractive $TEMP_WIFI_NETWORKS_FILE
  1257. if [ -f $TEMP_WIFI_NETWORKS_FILE ]; then
  1258. cp "$TEMP_WIFI_NETWORKS_FILE" "$WIFI_NETWORKS_FILE"
  1259. rm $TEMP_WIFI_NETWORKS_FILE
  1260. "${PROJECT_NAME}-wifi" --networks "$WIFI_NETWORKS_FILE"
  1261. create_wifi_startup_script
  1262. if [[ $(wifi_is_running) == "1" ]]; then
  1263. dialog --title $"Wifi Settings" \
  1264. --msgbox $"Wifi settings were changed." 6 60
  1265. else
  1266. dialog --title $"Wifi Settings" \
  1267. --msgbox $"Wifi settings were changed. You will need to restart the system with ethernet cable removed for the changes to take effect." 7 60
  1268. fi
  1269. else
  1270. remove_wifi_startup_script
  1271. fi
  1272. }
  1273. function wifi_edit_networks {
  1274. if [ -f /etc/hostapd/hostapd.conf ]; then
  1275. return
  1276. fi
  1277. if [ ! -f "$WIFI_NETWORKS_FILE" ]; then
  1278. { echo $'# Add wifi networks as follows:';
  1279. echo '#';
  1280. echo $'# MySSID';
  1281. echo $'# wpa2-psk';
  1282. echo $'# myWifiPassphrase';
  1283. echo '#';
  1284. echo $'# AnotherSSID';
  1285. echo $'# none';
  1286. echo '#'; } > "$WIFI_NETWORKS_FILE"
  1287. fi
  1288. editor "$WIFI_NETWORKS_FILE"
  1289. "${PROJECT_NAME}-wifi" --networks "$WIFI_NETWORKS_FILE"
  1290. }
  1291. function hotspot_settings {
  1292. data=$(mktemp 2>/dev/null)
  1293. dialog --backtitle $"Freedombone Control Panel" \
  1294. --title $"Hotspot Settings" \
  1295. --form $"" 10 60 4 \
  1296. $"Enabled (yes/no):" 1 1 "$WIFI_HOTSPOT" 1 24 5 5 \
  1297. $"SSID:" 2 1 "$WIFI_SSID" 2 24 256 256 \
  1298. $"Type (wpa2-psk/none):" 3 1 "$WIFI_TYPE" 3 24 10 10 \
  1299. $"Passphrase:" 4 1 "$WIFI_PASSPHRASE" 4 24 256 256 \
  1300. 2> "$data"
  1301. sel=$?
  1302. case $sel in
  1303. 1) rm -f "$data"
  1304. return;;
  1305. 255) rm -f "$data"
  1306. return;;
  1307. esac
  1308. TEMP_WIFI_HOTSPOT=$(sed -n 1p < "$data")
  1309. TEMP_WIFI_SSID=$(sed -n 2p < "$data")
  1310. TEMP_WIFI_TYPE=$(sed -n 3p < "$data")
  1311. TEMP_WIFI_PASSPHRASE=$(sed -n 4p < "$data")
  1312. rm -f "$data"
  1313. if [ ${#TEMP_WIFI_SSID} -lt 2 ]; then
  1314. return
  1315. fi
  1316. if [ ${#TEMP_WIFI_TYPE} -lt 2 ]; then
  1317. return
  1318. fi
  1319. WIFI_EXTRA=''
  1320. if [[ $TEMP_WIFI_HOTSPOT == $'yes' || $TEMP_WIFI_HOTSPOT == $'y' || $TEMP_WIFI_HOTSPOT == $'on' ]]; then
  1321. TEMP_WIFI_HOTSPOT='yes'
  1322. else
  1323. TEMP_WIFI_HOTSPOT='no'
  1324. if [ -f "$WIFI_NETWORKS_FILE" ]; then
  1325. WIFI_EXTRA="--networks $WIFI_NETWORKS_FILE"
  1326. fi
  1327. fi
  1328. if [[ $TEMP_WIFI_TYPE != $'none' ]]; then
  1329. if [ ! "$TEMP_WIFI_PASSPHRASE" ]; then
  1330. dialog --title $"Wifi Settings" \
  1331. --msgbox $"No wifi hotspot passphrase was given" 6 40
  1332. return
  1333. fi
  1334. if [ ${#TEMP_WIFI_PASSPHRASE} -lt 2 ]; then
  1335. dialog --title $"Wifi Settings" \
  1336. --msgbox $"Wifi hotspot passphrase was too short" 6 40
  1337. return
  1338. fi
  1339. WIFI_HOTSPOT=$TEMP_WIFI_HOTSPOT
  1340. WIFI_SSID=$TEMP_WIFI_SSID
  1341. WIFI_TYPE=$TEMP_WIFI_TYPE
  1342. WIFI_PASSPHRASE=$TEMP_WIFI_PASSPHRASE
  1343. if ! "${PROJECT_NAME}-wifi" -i "$WIFI_INTERFACE" -s "$WIFI_SSID" -t "$WIFI_TYPE" -p "$WIFI_PASSPHRASE" --hotspot "$WIFI_HOTSPOT" "$WIFI_EXTRA"; then
  1344. echo $"Can't enable wifi hotspot"
  1345. any_key
  1346. fi
  1347. else
  1348. WIFI_HOTSPOT=$TEMP_WIFI_HOTSPOT
  1349. WIFI_SSID=$TEMP_WIFI_SSID
  1350. WIFI_TYPE=$TEMP_WIFI_TYPE
  1351. WIFI_PASSPHRASE=$TEMP_WIFI_PASSPHRASE
  1352. "${PROJECT_NAME}-wifi" -i "$WIFI_INTERFACE" -s "$WIFI_SSID" -t "$WIFI_TYPE" --hotspot "$WIFI_HOTSPOT" "$WIFI_EXTRA"
  1353. fi
  1354. # store any changes
  1355. write_config_param "WIFI_HOTSPOT" "$WIFI_HOTSPOT"
  1356. write_config_param "WIFI_SSID" "$WIFI_SSID"
  1357. write_config_param "WIFI_TYPE" "$WIFI_TYPE"
  1358. write_config_param "WIFI_PASSPHRASE" "$WIFI_PASSPHRASE"
  1359. dialog --title $"Wifi Settings" \
  1360. --msgbox $"Hotspot settings were changed" 6 40
  1361. }
  1362. function reinstall_mariadb {
  1363. dialog --title $"Reinstall MariaDB" \
  1364. --backtitle $"Freedombone Control Panel" \
  1365. --defaultno \
  1366. --yesno $"\\nThis should be a LAST RESORT, if the mysql daemon won't start. You will lose ALL databases and will then need to restore them from backup.\\n\\nAre you sure that you wish to continue?" 12 60
  1367. sel=$?
  1368. case $sel in
  1369. 1) return;;
  1370. 255) return;;
  1371. esac
  1372. clear
  1373. database_reinstall
  1374. dialog --title $"Reinstall MariaDB" \
  1375. --msgbox $"MariaDB has been reinstalled" 6 40
  1376. }
  1377. function email_extra_domains {
  1378. email_hostnames=$(grep "dc_other_hostnames" /etc/exim4/update-exim4.conf.conf | awk -F "'" '{print $2}')
  1379. data=$(mktemp 2>/dev/null)
  1380. dialog --title $"Email Domains" \
  1381. --backtitle $"Freedombone Control Panel" \
  1382. --inputbox $"Enter the list of email domains to use, separated by semicolons" 8 60 "$email_hostnames" 2>"$data"
  1383. sel=$?
  1384. case $sel in
  1385. 0)
  1386. emailhostnames=$(<"$data")
  1387. if [ ${#emailhostnames} -gt 2 ]; then
  1388. if [[ "$email_hostnames" != "$emailhostnames" ]]; then
  1389. if [[ "$emailhostnames" == *"."* ]]; then
  1390. if [[ "$emailhostnames" != *" "* ]]; then
  1391. sed -i "s|dc_other_hostnames=.*|dc_other_hostnames='$emailhostnames'|g" /etc/exim4/update-exim4.conf.conf
  1392. update-exim4.conf
  1393. dpkg-reconfigure --frontend noninteractive exim4-config
  1394. systemctl restart saslauthd
  1395. dialog --title $"Email Domains" \
  1396. --backtitle $"Freedombone Control Panel" \
  1397. --msgbox $"Email domains were changed" 6 50
  1398. else
  1399. dialog --title $"Email Domains not set" \
  1400. --backtitle $"Freedombone Control Panel" \
  1401. --msgbox $"There should be no spaces in the list" 6 50
  1402. fi
  1403. fi
  1404. fi
  1405. fi
  1406. ;;
  1407. esac
  1408. rm -f "$data"
  1409. }
  1410. function email_smtp_proxy {
  1411. MUTTRC_FILE=/home/$ADMIN_USER/.muttrc
  1412. if [ ! -f $MUTTRC_FILE ]; then
  1413. return
  1414. fi
  1415. data=$(mktemp 2>/dev/null)
  1416. dialog --backtitle $"Freedombone Control Panel" \
  1417. --title $"SMTP Proxy for $ADMIN_USER" \
  1418. --form $"You may need to proxy outgoing email via your ISP's mail server. If so enter the details below." 14 75 6 \
  1419. $"Enable proxy:" 1 1 "$SMTP_PROXY_ENABLE" 1 24 5 5 \
  1420. $"Protocol (smtp/smtps):" 2 1 "$SMTP_PROXY_PROTOCOL" 2 24 5 5 \
  1421. $"ISP mail server:" 3 1 "$SMTP_PROXY_SERVER" 3 24 40 10000 \
  1422. $"Port:" 4 1 "$SMTP_PROXY_PORT" 4 24 5 5 \
  1423. $"Username:" 5 1 "$SMTP_PROXY_USERNAME" 5 24 40 10000 \
  1424. $"Password:" 6 1 "$SMTP_PROXY_PASSWORD" 6 24 40 10000 \
  1425. 2> "$data"
  1426. sel=$?
  1427. case $sel in
  1428. 1) rm -f "$data"
  1429. return;;
  1430. 255) rm -f "$data"
  1431. return;;
  1432. esac
  1433. SMTP_PROXY_ENABLE=$(sed -n 1p < "$data")
  1434. SMTP_PROXY_PROTOCOL=$(sed -n 2p < "$data")
  1435. SMTP_PROXY_SERVER=$(sed -n 3p < "$data")
  1436. SMTP_PROXY_PORT=$(sed -n 4p < "$data")
  1437. SMTP_PROXY_USERNAME=$(sed -n 5p < "$data")
  1438. SMTP_PROXY_PASSWORD=$(sed -n 6p < "$data")
  1439. rm -f "$data"
  1440. # change muttrc
  1441. if [ "$SMTP_PROXY_ENABLE" != $'no' ]; then
  1442. if ! grep -q "set smtp_url" "$MUTTRC_FILE"; then
  1443. echo "set smtp_url=\"${SMTP_PROXY_PROTOCOL}://${SMTP_PROXY_USERNAME}:${SMTP_PROXY_PASSWORD}@${SMTP_PROXY_SERVER}:${SMTP_PROXY_PORT}/\"" >> "$MUTTRC_FILE"
  1444. else
  1445. sed -i "s|set smtp_url=.*|set smtp_url=\"${SMTP_PROXY_PROTOCOL}://${SMTP_PROXY_USERNAME}:${SMTP_PROXY_PASSWORD}@${SMTP_PROXY_SERVER}:${SMTP_PROXY_PORT}/\"|g" "$MUTTRC_FILE"
  1446. fi
  1447. sed -i 's|#set smtp_url|set smtp_url|g' "$MUTTRC_FILE"
  1448. else
  1449. if grep -q "set smtp_url" "$MUTTRC_FILE"; then
  1450. sed -i 's|set smtp_url|#set smtp_url|g' "$MUTTRC_FILE"
  1451. fi
  1452. fi
  1453. # save settings within the main configuration file
  1454. write_config_param "SMTP_PROXY_ENABLE" "$SMTP_PROXY_ENABLE"
  1455. write_config_param "SMTP_PROXY_PROTOCOL" "$SMTP_PROXY_PROTOCOL"
  1456. write_config_param "SMTP_PROXY_SERVER" "$SMTP_PROXY_SERVER"
  1457. write_config_param "SMTP_PROXY_PORT" "$SMTP_PROXY_PORT"
  1458. write_config_param "SMTP_PROXY_USERNAME" "$SMTP_PROXY_USERNAME"
  1459. write_config_param "SMTP_PROXY_PASSWORD" "$SMTP_PROXY_PASSWORD"
  1460. }
  1461. function menu_backup_restore {
  1462. while true
  1463. do
  1464. W=(1 $"Backup data to USB drive"
  1465. 2 $"Restore GPG key from USB keydrive"
  1466. 3 $"Restore data from USB drive"
  1467. 4 $"Reinstall mariadb"
  1468. 5 $"Configure remote backups"
  1469. 6 $"Restore from remote backup"
  1470. 7 $"Backup GPG key to USB (master keydrive)"
  1471. 8 $"Backup GPG key to USB (fragment keydrive)"
  1472. 9 $"Format a USB drive (LUKS encrypted)"
  1473. 10 $"Remove backups from a USB drive")
  1474. # shellcheck disable=SC2068
  1475. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Backup and Restore" --menu $"Choose an operation, or ESC for main menu:" 19 70 12 "${W[@]}" 3>&2 2>&1 1>&3)
  1476. if [ ! "$selection" ]; then
  1477. break
  1478. fi
  1479. case $selection in
  1480. 1) backup_data;;
  1481. 2) restore_gpg_key;;
  1482. 3) restore_data;;
  1483. 4) reinstall_mariadb;;
  1484. 5) configure_remote_backups;;
  1485. 6) restore_data_remote;;
  1486. 7) create_keydrive_master;;
  1487. 8) create_keydrive_fragment;;
  1488. 9) format_drive;;
  1489. 10) remove_backups;;
  1490. esac
  1491. done
  1492. }
  1493. function menu_email {
  1494. while true
  1495. do
  1496. W=(1 $"Add a user to a mailing list"
  1497. 2 $"Remove a user from a mailing list"
  1498. 3 $"Add an email rule"
  1499. 4 $"Block/Unblock an email address"
  1500. 5 $"Block/Unblock email with subject text"
  1501. 6 $"Outgoing Email Proxy"
  1502. 7 $"Extra email domains")
  1503. # shellcheck disable=SC2068
  1504. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Email Menu" --menu $"Choose an operation, or ESC for main menu:" 15 70 8 "${W[@]}" 3>&2 2>&1 1>&3)
  1505. if [ ! "$selection" ]; then
  1506. break
  1507. fi
  1508. case $selection in
  1509. 1) add_to_mailing_list;;
  1510. 2) remove_user_from_mailing_list;;
  1511. 3) email_rule;;
  1512. 4) block_unblock_email;;
  1513. 5) block_unblock_subject;;
  1514. 6) email_smtp_proxy;;
  1515. 7) email_extra_domains;;
  1516. esac
  1517. done
  1518. }
  1519. function domain_blocking_add {
  1520. data=$(mktemp 2>/dev/null)
  1521. dialog --title $"Block a domain or user" \
  1522. --backtitle $"Freedombone Control Panel" \
  1523. --inputbox $"Enter the domain name or GNU Social/postActiv/Pleroma nick@domain that you wish to block" 8 60 "" 2>"$data"
  1524. sel=$?
  1525. case $sel in
  1526. 0)
  1527. blocked_domain=$(<"$data")
  1528. if [ ${#blocked_domain} -gt 2 ]; then
  1529. if [[ "${blocked_domain}" == *'.'* ]]; then
  1530. firewall_block_domain "$blocked_domain"
  1531. if [[ "${blocked_domain}" != *'@'* ]]; then
  1532. dialog --title $"Block a domain" \
  1533. --msgbox $"The domain $blocked_domain has been blocked" 6 40
  1534. else
  1535. dialog --title $"Block a GNU Social/postActiv/Pleroma nickname" \
  1536. --msgbox $"$blocked_domain has been blocked" 6 40
  1537. fi
  1538. fi
  1539. fi
  1540. ;;
  1541. esac
  1542. rm -f "$data"
  1543. }
  1544. function ip_blocking_add {
  1545. data=$(mktemp 2>/dev/null)
  1546. dialog --title $"Block an IP address" \
  1547. --backtitle $"Freedombone Control Panel" \
  1548. --inputbox $"Enter the IP address that you wish to block" 8 60 "" 2>"$data"
  1549. sel=$?
  1550. case $sel in
  1551. 0)
  1552. blocked_ip=$(<"$data")
  1553. if [ ${#blocked_ip} -gt 2 ]; then
  1554. if [[ "${blocked_ip}" == *'.'* ]]; then
  1555. firewall_block_ip "$blocked_ip"
  1556. if [[ "${blocked_ip}" != *'@'* ]]; then
  1557. dialog --title $"Block an IP address" \
  1558. --msgbox $"The IP address $blocked_ip has been blocked" 6 40
  1559. fi
  1560. fi
  1561. fi
  1562. ;;
  1563. esac
  1564. rm -f "$data"
  1565. }
  1566. function domain_blocking_remove {
  1567. data=$(mktemp 2>/dev/null)
  1568. dialog --title $"Unblock a domain or user" \
  1569. --backtitle $"Freedombone Control Panel" \
  1570. --inputbox $"Enter the domain name or GNU Social/postActiv nick@domain that you wish to unblock" 8 60 "" 2>"$data"
  1571. sel=$?
  1572. case $sel in
  1573. 0)
  1574. unblocked_domain=$(<"$data")
  1575. if [ ${#unblocked_domain} -gt 2 ]; then
  1576. if [[ "${unblocked_domain}" == *'.'* ]]; then
  1577. firewall_unblock_domain "$unblocked_domain"
  1578. if [[ "${unblocked_domain}" != *'@'* ]]; then
  1579. dialog --title $"Unblock a domain" \
  1580. --msgbox $"The domain $unblocked_domain has been unblocked" 6 40
  1581. else
  1582. dialog --title $"Unblock a GNU Social/postActiv nickname" \
  1583. --msgbox $"$unblocked_domain has been unblocked" 6 40
  1584. fi
  1585. fi
  1586. fi
  1587. ;;
  1588. esac
  1589. rm -f "$data"
  1590. }
  1591. function ip_blocking_remove {
  1592. data=$(mktemp 2>/dev/null)
  1593. dialog --title $"Unblock an IP address" \
  1594. --backtitle $"Freedombone Control Panel" \
  1595. --inputbox $"Enter the IP address that you wish to unblock" 8 60 "" 2>"$data"
  1596. sel=$?
  1597. case $sel in
  1598. 0)
  1599. unblocked_ip=$(<"$data")
  1600. if [ ${#unblocked_ip} -gt 2 ]; then
  1601. if [[ "${unblocked_ip}" == *'.'* ]]; then
  1602. firewall_unblock_ip "$unblocked_ip"
  1603. if [[ "${unblocked_ip}" != *'@'* ]]; then
  1604. dialog --title $"Unblock an IP address" \
  1605. --msgbox $"The IP address $unblocked_ip has been unblocked" 6 40
  1606. fi
  1607. fi
  1608. fi
  1609. ;;
  1610. esac
  1611. rm -f "$data"
  1612. }
  1613. function domain_blocking_show {
  1614. if [ -f "$FIREWALL_DOMAINS" ]; then
  1615. clear
  1616. echo ''
  1617. echo $'The following domains or users have been blocked:'
  1618. echo ''
  1619. sort < "$FIREWALL_DOMAINS"
  1620. any_key
  1621. else
  1622. dialog --title $"Show blocked domains or users" \
  1623. --msgbox $"No domains or users are currently blocked" 6 40
  1624. fi
  1625. }
  1626. function domain_blocking {
  1627. while true
  1628. do
  1629. W=(1 $"Block a domain or user"
  1630. 2 $"Unblock a domain or user"
  1631. 3 $"Block an IP address"
  1632. 4 $"Unblock an IP address"
  1633. 5 $"Show blocked domains and users")
  1634. # shellcheck disable=SC2068
  1635. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Domain or User Blocking" --menu $"Choose an operation, or ESC for main menu:" 13 70 6 "${W[@]}" 3>&2 2>&1 1>&3)
  1636. if [ ! "$selection" ]; then
  1637. break
  1638. fi
  1639. case $selection in
  1640. 1) domain_blocking_add;;
  1641. 2) domain_blocking_remove;;
  1642. 3) ip_blocking_add;;
  1643. 4) ip_blocking_remove;;
  1644. 5) domain_blocking_show;;
  1645. esac
  1646. done
  1647. }
  1648. function menu_users {
  1649. while true
  1650. do
  1651. W=(1 $"Add a user"
  1652. 2 $"Delete a user"
  1653. 3 $"Change user password"
  1654. 4 $"Change user ssh public key"
  1655. 5 $"Reset password tries")
  1656. # shellcheck disable=SC2068
  1657. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Manage Users" --menu $"Choose an operation, or ESC for main menu:" 13 70 6 "${W[@]}" 3>&2 2>&1 1>&3)
  1658. if [ ! "$selection" ]; then
  1659. break
  1660. fi
  1661. case $selection in
  1662. 1) add_user;;
  1663. 2) delete_user;;
  1664. 3) change_password;;
  1665. 4) change_ssh_public_key;;
  1666. 5) reset_password_tries;;
  1667. esac
  1668. done
  1669. }
  1670. function wifi_enable {
  1671. disable_wifi='yes'
  1672. dialog --title $"Enable Wifi" \
  1673. --backtitle $"Freedombone Control Panel" \
  1674. --defaultno \
  1675. --yesno $"\\nDo you wish to enable wifi?" 10 50
  1676. sel=$?
  1677. case $sel in
  1678. 0) disable_wifi='no';;
  1679. 1) disable_wifi='yes';;
  1680. 255) return;;
  1681. esac
  1682. "${PROJECT_NAME}-wifi" --disable $disable_wifi
  1683. }
  1684. function add_clacks {
  1685. clacks=
  1686. data=$(mktemp 2>/dev/null)
  1687. dialog --title $"Add Clacks Overhead" \
  1688. --backtitle $"Freedombone Control Panel" \
  1689. --inputbox $"" 7 60 2>"$data"
  1690. sel=$?
  1691. case $sel in
  1692. 0)
  1693. clacks=$(<"$data")
  1694. if [ ${#clacks} -gt 1 ]; then
  1695. WEB_FILES="/etc/nginx/sites-available/*"
  1696. for f in $WEB_FILES
  1697. do
  1698. if grep -q "X-Clacks-Overhead" "$f"; then
  1699. sed -i "s|X-Clacks-Overhead .*|X-Clacks-Overhead \"GNU $clacks\";|g" "$f"
  1700. else
  1701. sed -i "/X-Content-Type-Options/a add_header X-Clacks-Overhead \"GNU $clacks\";" "$f"
  1702. fi
  1703. done
  1704. systemctl restart nginx
  1705. dialog --title $"Add Clacks Overhead" \
  1706. --msgbox $"\\nAdded for $clacks" 10 60
  1707. fi
  1708. ;;
  1709. esac
  1710. rm -f "$data"
  1711. }
  1712. function menu_wifi {
  1713. if [[ "$(wifi_exists)" == "0" ]]; then
  1714. dialog --title $"Wifi" \
  1715. --msgbox $"No wifi adaptors were detected" 6 40
  1716. return
  1717. fi
  1718. while true
  1719. do
  1720. status_str=$'Wifi OFF'
  1721. if [ -f /etc/hostapd/hostapd.conf ]; then
  1722. status_str=$'Hotspot ON'
  1723. else
  1724. if [ -f /etc/network/interfaces.d/wifi ]; then
  1725. status_str=$'Wifi ON'
  1726. fi
  1727. fi
  1728. W=(1 $"Enable or disable Wifi"
  1729. 2 $"Configure wifi networks"
  1730. 3 $"Manually edit wifi networks file"
  1731. 4 $"Hotspot settings")
  1732. # shellcheck disable=SC2068
  1733. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Wifi Menu" --menu $"${status_str}\\n\\nChoose an operation, or ESC for main menu:" 14 70 6 "${W[@]}" 3>&2 2>&1 1>&3)
  1734. if [ ! "$selection" ]; then
  1735. break
  1736. fi
  1737. case $selection in
  1738. 1) wifi_enable;;
  1739. 2) wifi_settings;;
  1740. 3) wifi_edit_networks;;
  1741. 4) hotspot_settings;;
  1742. esac
  1743. done
  1744. }
  1745. function menu_app_settings {
  1746. detect_installable_apps
  1747. applist=""
  1748. appnames=()
  1749. n=1
  1750. app_index=0
  1751. # shellcheck disable=SC2068
  1752. for a in ${APPS_AVAILABLE[@]}
  1753. do
  1754. if [[ ${APPS_INSTALLED[$app_index]} != "0" ]]; then
  1755. if [[ $(function_exists "configure_interactive_${a}") == "1" ]]; then
  1756. applist="$applist $n $a off"
  1757. n=$((n+1))
  1758. appnames+=("$a")
  1759. fi
  1760. fi
  1761. app_index=$((app_index+1))
  1762. done
  1763. if [ $n -le 1 ]; then
  1764. return
  1765. fi
  1766. backstr=$'Exit'
  1767. applist="$applist $n $backstr on"
  1768. appnames+=("Exit")
  1769. # shellcheck disable=SC2086
  1770. choice=$(dialog --stdout --backtitle $"Freedombone" \
  1771. --title $"Change settings for an App" \
  1772. --radiolist $'Choose:' \
  1773. 26 40 30 $applist)
  1774. # shellcheck disable=SC2181
  1775. if [ $? -eq 0 ]; then
  1776. app_index=$((choice-1))
  1777. chosen_app=${appnames[$app_index]}
  1778. if [[ $chosen_app != "Exit" ]]; then
  1779. "configure_interactive_${chosen_app}"
  1780. fi
  1781. fi
  1782. }
  1783. function menu_top_level {
  1784. while true
  1785. do
  1786. W=(1 $"About this system"
  1787. 2 $"Backup and Restore"
  1788. 3 $"App Settings"
  1789. 4 $"Add/Remove Apps"
  1790. 5 $"Logging on/off"
  1791. 6 $"Ping enable/disable"
  1792. 7 $"Manage Users"
  1793. 8 $"Email Menu"
  1794. 9 $"Domain or User Blocking"
  1795. 10 $"Security Settings"
  1796. 11 $"Change the name of this system"
  1797. 12 $"Set a static local IP address"
  1798. 13 $"Wifi menu"
  1799. 14 $"Add Clacks"
  1800. 15 $"Check for updates"
  1801. 16 $"Power off the system"
  1802. 17 $"Restart the system")
  1803. # shellcheck disable=SC2068
  1804. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Administrator Control Panel" --menu $"Choose an operation, or ESC to exit:" 25 60 25 "${W[@]}" 3>&2 2>&1 1>&3)
  1805. if [ ! "$selection" ]; then
  1806. break
  1807. fi
  1808. please_wait
  1809. case $selection in
  1810. 1) show_about;;
  1811. 2) menu_backup_restore;;
  1812. 3) menu_app_settings;;
  1813. 4) if ! /usr/local/bin/addremove; then
  1814. any_key
  1815. fi
  1816. ;;
  1817. 5) logging_on_off;;
  1818. 6) ping_enable_disable;;
  1819. 7) menu_users;;
  1820. 8) menu_email;;
  1821. 9) domain_blocking;;
  1822. 10) security_settings;;
  1823. 11) change_system_name;;
  1824. 12) set_static_IP;;
  1825. 13) menu_wifi;;
  1826. 14) add_clacks;;
  1827. 15) check_for_updates;;
  1828. 16) shut_down_system;;
  1829. 17) restart_system;;
  1830. esac
  1831. done
  1832. }
  1833. if [ ! -f "$COMPLETION_FILE" ]; then
  1834. echo $'This command should only be run on an installed Freedombone system'
  1835. exit 1
  1836. fi
  1837. ADMIN_USER=$(get_completion_param "Admin user")
  1838. menu_top_level
  1839. clear
  1840. cat /etc/motd
  1841. exit 0