freedombone-controlpanel 64KB

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