freedombone-controlpanel 74KB

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