filtron.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck disable=SC2119,SC2001
  5. # shellcheck source=utils/lib.sh
  6. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  7. source_dot_config
  8. # ----------------------------------------------------------------------------
  9. # config
  10. # ----------------------------------------------------------------------------
  11. FILTRON_URL_PATH="${FILTRON_URL_PATH:-$(echo "${PUBLIC_URL}" \
  12. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  13. [[ "${FILTRON_URL_PATH}" == "${PUBLIC_URL}" ]] && FILTRON_URL_PATH=/
  14. FILTRON_ETC="/etc/filtron"
  15. FILTRON_RULES="$FILTRON_ETC/rules.json"
  16. FILTRON_API="127.0.0.1:4005"
  17. FILTRON_LISTEN="127.0.0.1:4004"
  18. FILTRON_TARGET="127.0.0.1:8888"
  19. SERVICE_NAME="filtron"
  20. SERVICE_USER="${SERVICE_NAME}"
  21. SERVICE_HOME="/home/${SERVICE_USER}"
  22. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  23. # shellcheck disable=SC2034
  24. SERVICE_GROUP="${SERVICE_USER}"
  25. GO_ENV="${SERVICE_HOME}/.go_env"
  26. GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
  27. GO_TAR=$(basename "$GO_PKG_URL")
  28. # Apache Settings
  29. APACHE_FILTRON_SITE="searx.conf"
  30. # shellcheck disable=SC2034
  31. CONFIG_FILES=(
  32. "${FILTRON_RULES}"
  33. "${SERVICE_SYSTEMD_UNIT}"
  34. )
  35. # ----------------------------------------------------------------------------
  36. usage() {
  37. # ----------------------------------------------------------------------------
  38. # shellcheck disable=SC1117
  39. cat <<EOF
  40. usage:
  41. $(basename "$0") shell
  42. $(basename "$0") install [all|user]
  43. $(basename "$0") update [filtron]
  44. $(basename "$0") remove [all]
  45. $(basename "$0") activate [service]
  46. $(basename "$0") deactivate [service]
  47. $(basename "$0") inspect [service]
  48. $(basename "$0") option [debug-on|debug-off]
  49. $(basename "$0") apache [install|remove]
  50. shell
  51. start interactive shell from user ${SERVICE_USER}
  52. install / remove
  53. all: complete setup of filtron service
  54. user: add/remove service user '$SERVICE_USER' at $SERVICE_HOME
  55. update filtron
  56. Update filtron installation of user ${SERVICE_USER}
  57. activate service
  58. activate and start service daemon (systemd unit)
  59. deactivate service
  60. stop and deactivate service daemon (systemd unit)
  61. inspect service
  62. show service status and log
  63. option
  64. set one of the available options
  65. apache
  66. install: apache site with a reverse proxy (ProxyPass)
  67. remove: apache site ${APACHE_FILTRON_SITE}
  68. If needed change the environment variable PUBLIC_URL of your WEB service in the
  69. ${DOT_CONFIG#"$REPO_ROOT/"} file:
  70. PUBLIC_URL : ${PUBLIC_URL}
  71. PUBLIC_HOST : ${PUBLIC_HOST}
  72. EOF
  73. [ ! -z ${1+x} ] && echo -e "$1"
  74. }
  75. main() {
  76. rst_title "$SERVICE_NAME" part
  77. required_commands \
  78. dpkg apt-get install git wget curl \
  79. || exit
  80. local _usage="ERROR: unknown or missing $1 command $2"
  81. case $1 in
  82. --source-only) ;;
  83. -h|--help) usage; exit 0;;
  84. shell)
  85. sudo_or_exit
  86. interactive_shell
  87. ;;
  88. inspect)
  89. case $2 in
  90. service)
  91. sudo_or_exit
  92. inspect_service
  93. ;;
  94. *) usage "$_usage"; exit 42;;
  95. esac ;;
  96. install)
  97. sudo_or_exit
  98. case $2 in
  99. all) install_all ;;
  100. user) assert_user ;;
  101. *) usage "$_usage"; exit 42;;
  102. esac ;;
  103. update)
  104. sudo_or_exit
  105. case $2 in
  106. filtron) update_filtron ;;
  107. *) usage "$_usage"; exit 42;;
  108. esac ;;
  109. remove)
  110. sudo_or_exit
  111. case $2 in
  112. all) remove_all;;
  113. user) remove_user ;;
  114. *) usage "$_usage"; exit 42;;
  115. esac ;;
  116. activate)
  117. sudo_or_exit
  118. case $2 in
  119. service) activate_service ;;
  120. *) usage "$_usage"; exit 42;;
  121. esac ;;
  122. deactivate)
  123. sudo_or_exit
  124. case $2 in
  125. service) deactivate_service ;;
  126. *) usage "$_usage"; exit 42;;
  127. esac ;;
  128. apache)
  129. sudo_or_exit
  130. case $2 in
  131. install) install_apache_site ;;
  132. remove) remove_apache_site ;;
  133. *) usage "$_usage"; exit 42;;
  134. esac ;;
  135. option)
  136. sudo_or_exit
  137. case $2 in
  138. debug-on) echo; enable_debug ;;
  139. debug-off) echo; disable_debug ;;
  140. *) usage "$_usage"; exit 42;;
  141. esac ;;
  142. *) usage "ERROR: unknown or missing command $1"; exit 42;;
  143. esac
  144. }
  145. install_all() {
  146. rst_title "Install $SERVICE_NAME (service)"
  147. assert_user
  148. wait_key
  149. install_go
  150. wait_key
  151. install_filtron
  152. wait_key
  153. install_service
  154. wait_key
  155. echo
  156. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  157. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  158. fi
  159. if apache_is_installed; then
  160. info_msg "Apache is installed on this host."
  161. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  162. install_apache_site
  163. fi
  164. fi
  165. if ask_yn "Do you want to inspect the installation?" Yn; then
  166. inspect_service
  167. fi
  168. }
  169. remove_all() {
  170. rst_title "De-Install $SERVICE_NAME (service)"
  171. rst_para "\
  172. It goes without saying that this script can only be used to remove
  173. installations that were installed with this script."
  174. remove_service
  175. wait_key
  176. remove_user
  177. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  178. if service_is_available "${PUBLIC_URL}"; then
  179. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  180. fi
  181. }
  182. install_service() {
  183. rst_title "Install System-D Unit ${SERVICE_NAME}.service" section
  184. echo
  185. install_template "${SERVICE_SYSTEMD_UNIT}" root root 644
  186. wait_key
  187. activate_service
  188. }
  189. remove_service() {
  190. if ! ask_yn "Do you really want to deinstall $SERVICE_NAME?"; then
  191. return
  192. fi
  193. deactivate_service
  194. rm "${SERVICE_SYSTEMD_UNIT}" 2>&1 | prefix_stdout
  195. }
  196. activate_service() {
  197. rst_title "Activate $SERVICE_NAME (service)" section
  198. echo
  199. tee_stderr <<EOF | bash 2>&1
  200. systemctl enable $SERVICE_NAME.service
  201. systemctl restart $SERVICE_NAME.service
  202. EOF
  203. tee_stderr <<EOF | bash 2>&1
  204. systemctl status --no-pager $SERVICE_NAME.service
  205. EOF
  206. }
  207. deactivate_service() {
  208. rst_title "De-Activate $SERVICE_NAME (service)" section
  209. echo
  210. tee_stderr <<EOF | bash 2>&1 | prefix_stdout
  211. systemctl stop $SERVICE_NAME.service
  212. systemctl disable $SERVICE_NAME.service
  213. EOF
  214. }
  215. user_is_available() {
  216. sudo -i -u "$SERVICE_USER" echo \$HOME &>/dev/null
  217. }
  218. assert_user() {
  219. rst_title "user $SERVICE_USER" section
  220. echo
  221. tee_stderr 1 <<EOF | bash | prefix_stdout
  222. sudo -H adduser --shell /bin/bash --system --home $SERVICE_HOME \
  223. --disabled-password --group --gecos 'Filtron' $SERVICE_USER
  224. sudo -H usermod -a -G shadow $SERVICE_USER
  225. groups $SERVICE_USER
  226. EOF
  227. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  228. export SERVICE_HOME
  229. echo "export SERVICE_HOME=$SERVICE_HOME"
  230. cat > "$GO_ENV" <<EOF
  231. export GOPATH=\$HOME/go-apps
  232. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  233. EOF
  234. echo "Environment $GO_ENV has been setup."
  235. tee_stderr <<EOF | sudo -i -u $SERVICE_USER
  236. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  237. EOF
  238. }
  239. remove_user() {
  240. rst_title "Drop $SERVICE_USER HOME" section
  241. if ask_yn "Do you really want to drop $SERVICE_USER home folder?"; then
  242. userdel -r -f "$SERVICE_USER" 2>&1 | prefix_stdout
  243. else
  244. rst_para "Leave HOME folder $(du -sh "$SERVICE_HOME") unchanged."
  245. fi
  246. }
  247. interactive_shell(){
  248. echo "// exit with ${_BCyan}CTRL-D${_creset}"
  249. sudo -H -u ${SERVICE_USER} -i
  250. }
  251. _service_prefix=" |$SERVICE_USER| "
  252. go_is_available() {
  253. sudo -i -u "$SERVICE_USER" which go &>/dev/null
  254. }
  255. install_go() {
  256. rst_title "Install Go in user's HOME" section
  257. rst_para "download and install go binary .."
  258. cache_download "${GO_PKG_URL}" "${GO_TAR}"
  259. tee_stderr 0.1 <<EOF | sudo -i -u "$SERVICE_USER" | prefix_stdout "$_service_prefix"
  260. echo \$PATH
  261. echo \$GOPATH
  262. mkdir -p \$HOME/local
  263. rm -rf \$HOME/local/go
  264. tar -C \$HOME/local -xzf ${CACHE}/${GO_TAR}
  265. EOF
  266. sudo -i -u "$SERVICE_USER" <<EOF | prefix_stdout
  267. ! which go >/dev/null && echo "ERROR - Go Installation not found in PATH!?!"
  268. which go >/dev/null && go version && echo "congratulations -- Go installation OK :)"
  269. EOF
  270. }
  271. filtron_is_installed() {
  272. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  273. }
  274. install_filtron() {
  275. rst_title "Install filtron in user's ~/go-apps" section
  276. echo
  277. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_service_prefix"
  278. go get -v -u github.com/asciimoo/filtron
  279. EOF
  280. install_template --no-eval "$FILTRON_RULES" root root 644
  281. }
  282. update_filtron() {
  283. rst_title "Update filtron" section
  284. echo
  285. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_service_prefix"
  286. go get -v -u github.com/asciimoo/filtron
  287. EOF
  288. }
  289. inspect_service() {
  290. rst_title "service status & log"
  291. cat <<EOF
  292. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  293. PUBLIC_URL : ${PUBLIC_URL}
  294. PUBLIC_HOST : ${PUBLIC_HOST}
  295. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  296. FILTRON_API : ${FILTRON_API}
  297. FILTRON_LISTEN : ${FILTRON_LISTEN}
  298. FILTRON_TARGET : ${FILTRON_TARGET}
  299. EOF
  300. apache_is_installed && info_msg "Apache is installed."
  301. if user_is_available; then
  302. info_msg "service account $SERVICE_USER available."
  303. else
  304. err_msg "service account $SERVICE_USER not available!"
  305. fi
  306. if go_is_available; then
  307. info_msg "~$SERVICE_USER: go is installed"
  308. else
  309. err_msg "~$SERVICE_USER: go is not installed"
  310. fi
  311. if filtron_is_installed; then
  312. info_msg "~$SERVICE_USER: filtron app is installed"
  313. else
  314. err_msg "~$SERVICE_USER: filtron app is not installed!"
  315. fi
  316. if ! service_is_available "http://${FILTRON_API}"; then
  317. err_msg "API not available at: http://${FILTRON_API}"
  318. fi
  319. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  320. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  321. fi
  322. if ! service_is_available ""http://${FILTRON_TARGET}"" ; then
  323. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  324. fi
  325. if ! service_is_available "${PUBLIC_URL}"; then
  326. err_msg "Public service at ${PUBLIC_URL} is not available!"
  327. fi
  328. local _debug_on
  329. if ask_yn "Enable filtron debug mode?"; then
  330. enable_debug
  331. _debug_on=1
  332. fi
  333. echo
  334. systemctl --no-pager -l status filtron.service
  335. echo
  336. # shellcheck disable=SC2059
  337. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  338. read -r -s -n1 -t 2
  339. echo
  340. while true; do
  341. trap break 2
  342. journalctl -f -u filtron
  343. done
  344. if [[ $_debug_on == 1 ]]; then
  345. disable_debug
  346. fi
  347. return 0
  348. }
  349. enable_debug() {
  350. info_msg "try to enable debug mode ..."
  351. python <<EOF
  352. import sys, json
  353. debug = {
  354. u'name': u'debug request'
  355. , u'filters': []
  356. , u'interval': 0
  357. , u'limit': 0
  358. , u'actions': [{u'name': u'log'}]
  359. }
  360. with open('$FILTRON_RULES') as rules:
  361. j = json.load(rules)
  362. pos = None
  363. for i in range(len(j)):
  364. if j[i].get('name') == 'debug request':
  365. pos = i
  366. break
  367. if pos is not None:
  368. j[pos] = debug
  369. else:
  370. j.append(debug)
  371. with open('$FILTRON_RULES', 'w') as rules:
  372. json.dump(j, rules, indent=2, sort_keys=True)
  373. EOF
  374. systemctl restart "${SERVICE_NAME}.service"
  375. }
  376. disable_debug() {
  377. info_msg "try to disable debug mode ..."
  378. python <<EOF
  379. import sys, json
  380. with open('$FILTRON_RULES') as rules:
  381. j = json.load(rules)
  382. pos = None
  383. for i in range(len(j)):
  384. if j[i].get('name') == 'debug request':
  385. pos = i
  386. break
  387. if pos is not None:
  388. del j[pos]
  389. with open('$FILTRON_RULES', 'w') as rules:
  390. json.dump(j, rules, indent=2, sort_keys=True)
  391. EOF
  392. systemctl restart "${SERVICE_NAME}.service"
  393. }
  394. install_apache_site() {
  395. rst_title "Install Apache site $APACHE_FILTRON_SITE"
  396. rst_para "\
  397. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
  398. ! apache_is_installed && err_msg "Apache is not installed."
  399. if ! ask_yn "Do you really want to continue?"; then
  400. return
  401. fi
  402. a2enmod headers
  403. a2enmod proxy
  404. a2enmod proxy_http
  405. echo
  406. apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
  407. info_msg "testing public url .."
  408. if ! service_is_available "${PUBLIC_URL}"; then
  409. err_msg "Public service at ${PUBLIC_URL} is not available!"
  410. fi
  411. }
  412. remove_apache_site() {
  413. rst_title "Remove Apache site $APACHE_FILTRON_SITE"
  414. rst_para "\
  415. This removes apache site ${APACHE_FILTRON_SITE}."
  416. ! apache_is_installed && err_msg "Apache is not installed."
  417. if ! ask_yn "Do you really want to continue?"; then
  418. return
  419. fi
  420. apache_remove_site "$APACHE_FILTRON_SITE"
  421. }
  422. # ----------------------------------------------------------------------------
  423. main "$@"
  424. # ----------------------------------------------------------------------------