/ Scripts / functions.sh
functions.sh
   1  #!/bin/bash
   2  
   3  
   4  # shellcheck source=./Scripts/defaults.sh
   5  . "${HOME}"/RoninDojo/Scripts/defaults.sh
   6  
   7  #
   8  # Main function runs at beginning of script execution
   9  #
  10  _main() {
  11  
  12      # Setup Manjaro users into the utility branch
  13      if [ ! -f "${ronin_data_systeminstall}" ]; then
  14          if [ -f /etc/lbs-release ] && grep "Manjaro" "/etc/lsb-release"; then
  15              . "${ronin_scripts_dir}"/update.sh
  16              _update_40
  17          fi
  18      fi
  19      
  20  }
  21  
  22  _call_update_scripts() {
  23      # shellcheck source=./Scripts/update.sh
  24      . "${HOME}"/RoninDojo/Scripts/update.sh
  25  
  26      mustReboot=0
  27  
  28      _update_24; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); # Fix hosts file, rerun always in case OS update reverts it
  29      test -f "${ronin_updates_data_dir}/40-"* || { _update_40; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # The last 1.x update ever
  30      test -f "${ronin_updates_data_dir}/43-"* || { _update_43; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # v2.1.0: tor upgrade
  31      test -f "${ronin_updates_data_dir}/44-"* || { _update_44; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # Ronin UI fix for 2.1.0
  32      test -f "${ronin_updates_data_dir}/45-"* || { _update_45; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # v2.0.1: Docker daemon.json update
  33      test -f "${ronin_updates_data_dir}/46-"* || { _update_46; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # Remove autologin
  34      test -f "${ronin_updates_data_dir}/47-"* || { _update_47; mustReboot=$(( $? == 2 ? 1 : $mustReboot )); } # Fix NOPASSWD
  35  
  36      if [ $mustReboot == 1 ]; then
  37          _stop_dojo
  38          sudo systemctl reboot
  39          exit 0
  40      fi
  41  }
  42  
  43  _skip_update_scripts() {
  44      if [ ! -f "${ronin_data_systeminstall}" ]; then
  45          for i in $(seq 1 9); do
  46              echo "skipped" > "${ronin_updates_data_dir}/0${i}-$(date +%m-%d-%Y)"
  47          done
  48          for i in $(seq 10 47); do # make sure the upper bound of this for loop here, stays up-to-date with the update numbering
  49              echo "skipped" > "${ronin_updates_data_dir}/${i}-$(date +%m-%d-%Y)"
  50          done
  51      fi
  52  }
  53  
  54  #
  55  # Prints a message in the RoninDojo human messaging format
  56  # Usage: _print_message "The billboard message here" ["extra lines below the billboard here" [..]]
  57  #
  58  _print_message() {
  59      cat <<EOF
  60  ${red}
  61  ***
  62  $1
  63  ***
  64  ${nc}
  65  EOF
  66      while [ $# -gt 1 ]; do
  67          echo $2
  68          shift 1
  69      done
  70  }
  71  
  72  #
  73  # Prints an error message in the RoninDojo human messaging format
  74  #
  75  _print_error_message() {
  76      cat >&2 <<EOF
  77  ${red}
  78  ***
  79  ERROR: $1
  80  ***
  81  ${nc}
  82  EOF
  83  }
  84  
  85  #
  86  # Upgrade the system packages
  87  #
  88  _upgrade_system_packages() {
  89      sudo apt-get -y update
  90      sudo apt-get -y upgrade
  91  
  92      _setup_tor
  93  
  94      return 0
  95  }
  96  
  97  #create a directory at the given path argument
  98  _create_dir() {
  99      if test ! -d "${1}"; then
 100          mkdir -p "${1}"
 101      fi
 102  }
 103  
 104  #
 105  # Random Password
 106  #
 107  _rand_passwd() {
 108      local _length
 109      _length="${1:-16}"
 110  
 111      tr -dc 'a-zA-Z0-9' </dev/urandom | head -c"${_length}"
 112  }
 113  
 114  #
 115  # Load user defined variables
 116  #
 117  _load_user_conf() {
 118      if [ -f "${ronin_user_conf}" ]; then
 119        . "${ronin_user_conf}"
 120      fi
 121  }
 122  
 123  #
 124  # Set systemd unit dependencies for docker and tor unit files
 125  # to depend on ${install_dir} mount point
 126  #
 127  _set_RequiresMountsFor_necessary_services() {
 128      _load_user_conf
 129  
 130      local tmp systemd_mountpoint
 131  
 132      tmp=${install_dir:1}               # Remove leading '/'
 133      systemd_mountpoint=${tmp////-}     # Replace / with -
 134  
 135      for x in docker tor; do
 136          if [ -f "/etc/systemd/system/${x}.service.d/override.conf" ]; then
 137              continue
 138          fi
 139  
 140          test -d "/etc/systemd/system/${x}.service.d" || sudo mkdir "/etc/systemd/system/${x}.service.d"
 141  
 142          if [ -f "/etc/systemd/system/${systemd_mountpoint}.mount" ]; then
 143              sudo tee "/etc/systemd/system/${x}.service.d/override.conf" <<EOF >/dev/null
 144  [Unit]
 145  RequiresMountsFor=${install_dir}
 146  EOF
 147          fi
 148  
 149          sudo systemctl daemon-reload
 150      done
 151  }
 152  
 153  #
 154  # For 2.0.2 and older versions of RoninOS
 155  #
 156  _disable_autologin() {
 157      sudo sed -i 's|^.*autologin.*$|ExecStart=-/sbin/agetty --noclear %I \$TERM|' "/etc/systemd/system/getty@tty1.service.d/override.conf"
 158  }
 159  
 160  #
 161  # Sets timeout for sudo prompt to 15mins
 162  #
 163  _set_sudo_timeout() {
 164      if [ ! -f /etc/sudoers.d/21-ronindojo ]; then
 165          sudo tee "/etc/sudoers.d/21-ronindojo" <<EOF >/dev/null
 166  Defaults env_reset,timestamp_timeout=15
 167  EOF
 168      fi
 169  }
 170  
 171  #
 172  # Installs a package if not yet installed, return false if an install failed.
 173  # Usage: _install_pkg_if_missing [--update-mirrors] package1 [pacakge2[..]]
 174  #
 175  _install_pkg_if_missing() {
 176      if [ $# -eq 0 ]; then
 177          echo "No arguments supplied"
 178          return 1
 179      fi
 180  
 181      for pkg in "$@"; do
 182          if dpkg -s "$pkg" >/dev/null 2>&1; then
 183              _print_message "${pkg} is already installed"
 184          else
 185              _print_message "Installing ${pkg}..."
 186              if ! sudo apt-get -y install "${pkg}"; then
 187                  _print_error_message "${pkg} failed to install!"
 188                  return 1
 189              fi
 190          fi
 191      done
 192  
 193      return 0
 194  }
 195  
 196  
 197  
 198  #
 199  # Countdown timer
 200  # Usage: _sleep <seconds> --msg "your message"
 201  #
 202  _sleep() {
 203      local secs msg verbose
 204      secs=1 verbose=false
 205  
 206      # Parse Arguments
 207      while [ $# -gt 0 ]; do
 208          case "$1" in
 209              (*[0-9]*)
 210                  secs="$1"
 211                  shift
 212                  ;;
 213              --msg)
 214                  msg="$2"
 215                  verbose=true
 216                  shift 2
 217                  ;;
 218          esac
 219      done
 220  
 221      while [ "$secs" -gt 0 ]; do
 222          if $verbose; then
 223              printf "%s%s %s\033[0K seconds...%s\r" "${red}" "${msg}" "${secs}" "${nc}"
 224          fi
 225          sleep 1
 226          : $((secs--))
 227      done
 228      printf "\n" # Add new line
 229  }
 230  
 231  #
 232  # Pause & return or continue
 233  #
 234  _pause() {
 235      _print_message "Press any key to ${1}..."
 236      read -n 1 -r -s
 237  }
 238  
 239  #
 240  # Check if unit file exist
 241  #
 242  _systemd_unit_exist() {
 243      local service
 244      service="$1"
 245  
 246      if systemctl cat -- "$service" ; then
 247          return 0
 248      else
 249          return 1
 250      fi
 251  }
 252  
 253  #
 254  # Returns whether systemd unit service is active
 255  #
 256  _is_active() {
 257      local service
 258      service="$1"
 259  
 260      if systemctl is-active --quiet "$service"; then
 261          return 0
 262      else
 263          return 1
 264      fi
 265  }
 266  
 267  #
 268  # Starts systemd unit service
 269  #
 270  _start_service() {
 271      local service
 272      service="$1"
 273  
 274      sudo systemctl start --quiet "$service"
 275  }
 276  
 277  #
 278  # Starts systemd unit service if inactive
 279  #
 280  _start_service_if_inactive() {
 281      local service
 282      service="$1"
 283  
 284      if ! _is_active "$service"; then
 285          _start_service "$service"
 286      fi
 287  }
 288  
 289  #
 290  # Setup torrc
 291  #
 292  _setup_tor() {
 293      _load_user_conf
 294  
 295      _print_message "Setting up the Tor service..."
 296  
 297      if [ ! -d "${install_dir_tor}" ]; then
 298          sudo mkdir "${install_dir_tor}"
 299          sudo chown -R tor:tor "${install_dir_tor}"
 300      fi
 301  
 302      if ! grep "User tor" /etc/tor/torrc; then
 303          sudo sed -i '$a\User tor' /etc/tor/torrc
 304      fi
 305  
 306      if grep -E "^DataDirectory\s+.+$" /etc/tor/torrc 1>/dev/null; then
 307          sudo sed -i "s:^DataDirectory .*$:DataDirectory ${install_dir_tor}:" /etc/tor/torrc
 308      else
 309          sudo sed -i "a\DataDirectory ${install_dir_tor}" /etc/tor/torrc
 310      fi
 311  
 312      sudo cp "${ronin_dir}"/example.tor.service /usr/lib/systemd/system/tor.service
 313      sudo rm -rf /usr/lib/systemd/system/tor@* #remove unnecessary debian installed services
 314      sudo systemctl daemon-reload
 315  
 316      if ! systemctl is-enabled --quiet tor; then
 317          sudo systemctl enable --quiet tor
 318      fi
 319  
 320      if _is_active tor; then
 321          sudo systemctl stop --quiet tor
 322      fi
 323      sudo systemctl start --quiet tor
 324  }
 325  
 326  #
 327  # Is Fulcrum Server Installed
 328  #
 329  _is_fulcrum() {
 330      # shellcheck disable=SC2154 
 331      if [ "fulcrum" == "$(source ${dojo_path_my_dojo}"/conf/docker-indexer.conf"; echo "${INDEXER_TYPE}")" ]; then
 332          return 0
 333      fi
 334  
 335      return 1
 336  }
 337  
 338  #
 339  # Is Electrs Server Installed
 340  #
 341  _is_electrs() {
 342      # shellcheck disable=SC2154 
 343      if [ "electrs" == "$(source ${dojo_path_my_dojo}"/conf/docker-indexer.conf"; echo "${INDEXER_TYPE}")" ]; then
 344          return 0
 345      fi
 346  
 347      return 1
 348  }
 349  
 350  #
 351  # Is Samourai Indexer Server Installed
 352  #
 353  _is_addrindexrs() {
 354      # shellcheck disable=SC2154 
 355      if [ "addrindexrs" == "$(source ${dojo_path_my_dojo}"/conf/docker-indexer.conf"; echo "${INDEXER_TYPE}")" ]; then
 356          return 0
 357      fi
 358  
 359      return 1
 360  }
 361  
 362  #
 363  # Ronin UI torrc
 364  #
 365  _ronin_ui_setup_tor() {
 366      if ! grep hidden_service_ronin_backend /etc/tor/torrc 1>/dev/null; then
 367          _print_message "Configuring RoninDojo Backend Tor Address..."
 368  
 369          sudo sed -i "/################ This section is just for relays/i\
 370  HiddenServiceDir ${install_dir_tor}/hidden_service_ronin_backend/\n\
 371  HiddenServiceVersion 3\n\
 372  HiddenServicePort 80 127.0.0.1:8470\n\
 373  " /etc/tor/torrc
 374  
 375          # restart tor service
 376          sudo systemctl restart --quiet tor
 377      fi
 378  
 379      # Populate or update "${ronin_data_dir}"/ronin-ui-tor-hostname with tor address
 380      if [ ! -f "${ronin_data_dir}"/ronin-ui-tor-hostname ]; then
 381          sudo bash -c "cat ${install_dir_tor}/hidden_service_ronin_backend/hostname >${ronin_data_dir}/ronin-ui-tor-hostname"
 382      elif ! sudo grep -q "$(sudo cat "${install_dir_tor}"/hidden_service_ronin_backend/hostname)" "${ronin_data_dir}"/ronin-ui-tor-hostname; then
 383          sudo bash -c "cat ${install_dir_tor}/hidden_service_ronin_backend/hostname >${ronin_data_dir}/ronin-ui-tor-hostname"
 384      fi
 385  }
 386  
 387  #
 388  # Check Ronin UI Installation
 389  #
 390  _is_ronin_ui() {
 391      _load_user_conf
 392  
 393      if [ ! -d "${ronin_ui_path}" ]; then
 394          return 1
 395      fi
 396  
 397      return 0
 398  }
 399  
 400  #
 401  # Setup pm2 server for Ronin-UI.
 402  # Description: Setup the service file first. service file is enabled and inactive. start the Ronin-UI pm2 instance. Save it.
 403  # Kill the current process. So we can use the persistant and restarting systemd instance. Prevents methods from competition for the PID.
 404  #
 405  _pm2_setup(){
 406     cd /home/ronindojo/Ronin-UI || exit
 407     pm2 startup
 408     sudo env PATH="$PATH:/usr/bin" /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ronindojo --hp /home/ronindojo
 409     pm2 start pm2.config.js
 410     pm2 save
 411     pm2 kill
 412     sudo systemctl start pm2-ronindojo
 413     cd - || exit
 414  }
 415  
 416  _ronin_debian_ui() {
 417  
 418      cd "${ronin_ui_path}" || exit
 419  
 420      _print_message "Performing pnpm install, please wait..."
 421  
 422      pnpm install --prod  || { printf "\n%s***\nRonin UI pnpm install failed...\n***%s\n" "${red}" "${nc}";exit; }
 423  
 424      _print_message "Performing Next start, please wait..."
 425  
 426      _pm2_setup
 427  
 428      # restart tor to ensure the backend is up and ready
 429      sudo systemctl restart tor
 430  
 431      # give tor time to rest and get set properly
 432      sleep 10s
 433  
 434      if [ ! -f "${ronin_data_dir}"/ronin-ui-tor-hostname ]; then
 435          sudo bash -c "cat ${install_dir_tor}/hidden_service_ronin_backend/hostname >${ronin_data_dir}/ronin-ui-tor-hostname"
 436      elif ! sudo grep -q "$(sudo cat "${install_dir_tor}"/hidden_service_ronin_backend/hostname)" "${ronin_data_dir}"/ronin-ui-tor-hostname; then
 437          sudo bash -c "cat ${install_dir_tor}/hidden_service_ronin_backend/hostname >${ronin_data_dir}/ronin-ui-tor-hostname"
 438      fi
 439  
 440      _ronin_ui_vhost
 441  
 442      sudo systemctl restart nginx
 443  
 444      cd - || exit
 445  }
 446  
 447  #
 448  # Install Ronin UI
 449  #
 450  _ronin_ui_install() {
 451      # shellcheck source=./Scripts/generated-credentials.sh
 452      . "${HOME}"/RoninDojo/Scripts/generated-credentials.sh
 453  
 454      _load_user_conf
 455  
 456      cd "${HOME}" || exit
 457  
 458      _print_message "Checking package dependencies for Ronin UI..."
 459      _sleep
 460  
 461      _install_pkg_if_missing "nginx"
 462      _install_pkg_if_missing "avahi-daemon"
 463  
 464      sudo npm i -g pnpm@7
 465  
 466      sudo npm install pm2 -g
 467  
 468      test -d "${ronin_ui_path}" || mkdir "${ronin_ui_path}"
 469      cd "${ronin_ui_path}" || exit
 470  
 471      wget -q "${roninui_version_file}" -O /tmp/version.json 2>/dev/null
 472  
 473      _file=$(jq -r .file /tmp/version.json)
 474      _shasum=$(jq -r .sha256 /tmp/version.json)
 475  
 476      wget -q https://ronindojo.io/downloads/RoninUI/"$_file" 2>/dev/null
 477  
 478      if ! echo "${_shasum} ${_file}" | sha256sum --check --status; then
 479          _bad_shasum=$(sha256sum ${_file})
 480          _print_error_message "Ronin UI archive verification failed! Valid sum is ${_shasum}, got ${_bad_shasum} instead..."
 481      fi
 482  
 483      tar xzf "$_file"
 484  
 485      rm "$_file" /tmp/version.json
 486  
 487          # Mark Ronin UI initialized if necessary
 488          if [ -e "${ronin_ui_init_file}" ]; then
 489            echo -e "{\"initialized\": true}\n" > ronin-ui.dat
 490          fi
 491  
 492          # Generate .env file
 493          echo "JWT_SECRET=$gui_jwt" > .env
 494          echo "NEXT_TELEMETRY_DISABLED=1" >> .env
 495  
 496      if [ "${roninui_version_staging}" = true ] ; then
 497          echo -e "VERSION_CHECK=staging\n" >> .env
 498      fi
 499  
 500      _print_message "Performing pnpm install, please wait..."
 501  
 502      pnpm install --prod || { printf "\n%s***\nRonin UI pnpm install failed...\n***%s\n" "${red}" "${nc}";exit; }
 503  
 504      _print_message "Performing Next start, please wait..."
 505  
 506      _pm2_setup
 507  
 508      _ronin_ui_setup_tor
 509  
 510      _ronin_ui_vhost
 511  
 512      _ronin_ui_avahi_service
 513  
 514      sudo systemctl restart nginx
 515  
 516      cd - || exit
 517  }
 518  
 519  #
 520  # Setup avahi service for ronindojo.local access
 521  #
 522  _ronin_ui_avahi_service() {
 523      if [ ! -f /etc/avahi/services/http.service ]; then
 524          sudo tee "/etc/avahi/services/http.service" <<EOF >/dev/null
 525  <?xml version="1.0" standalone='no'?><!--*-nxml-*-->
 526  <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
 527  <!-- This advertises the RoninDojo vhost -->
 528  <service-group>
 529   <name replace-wildcards="yes">%h Web Application</name>
 530    <service>
 531     <type>_http._tcp</type>
 532     <port>80</port>
 533    </service>
 534  </service-group>
 535  EOF
 536  
 537      fi
 538  
 539      sudo sed -i 's/hosts: .*$/hosts: files mdns_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns mdns/' /etc/nsswitch.conf
 540  
 541      if ! grep -q "host-name=ronindojo" /etc/avahi/avahi-daemon.conf; then
 542          sudo sed -i 's/.*host-name=.*$/host-name=ronindojo/' /etc/avahi/avahi-daemon.conf
 543      fi
 544  
 545      sudo systemctl restart avahi-daemon
 546  
 547      if ! systemctl is-enabled --quiet avahi-daemon; then
 548          sudo systemctl enable --quiet avahi-daemon
 549      fi
 550  
 551      return 0
 552  }
 553  
 554  #
 555  # Setup nginx reverse proxy for Ronin UI
 556  #
 557  _ronin_ui_vhost() {
 558      if [ ! -f /etc/nginx/sites-enabled/001-roninui ]; then
 559          local _tor_hostname
 560          _tor_hostname=$(sudo cat "${install_dir_tor}"/hidden_service_ronin_backend/hostname)
 561  
 562          test -d /etc/nginx/sites-enabled || sudo mkdir /etc/nginx/sites-enabled
 563          test -d /var/log/nginx || sudo mkdir -p /var/log/nginx
 564          test -d /etc/nginx/logs || sudo mkdir -p /etc/nginx/logs
 565  
 566          # Generate nginx.conf
 567          sudo tee "/etc/nginx/nginx.conf" <<EOF >/dev/null
 568  worker_processes  2;
 569  worker_rlimit_nofile 65535;
 570  
 571  error_log  logs/error.log;
 572  error_log  logs/error.log  notice;
 573  error_log  logs/error.log  info;
 574  
 575  events {
 576      worker_connections  8192;
 577      use epoll;
 578  
 579      multi_accept on;
 580  }
 581  
 582  http {
 583      default_type  application/octet-stream;
 584  
 585      log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
 586                        '\$status \$body_bytes_sent "\$http_referer" '
 587                        '"\$http_user_agent" "\$http_x_forwarded_for"';
 588  
 589      client_header_timeout 10m;
 590      client_body_timeout 10m;
 591      client_max_body_size 0;
 592      client_header_buffer_size 1k;
 593  
 594      keepalive_timeout  10 10;
 595  
 596      gzip  on;
 597      gzip_buffers 16 8k;
 598      gzip_comp_level 1;
 599      gzip_http_version 1.1;
 600      gzip_min_length 10;
 601      gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xlm+rss text/javascript image/x-icon application/vnd.ms-fontobject font/opentype application/x-font-ttf;
 602      gzip_vary off;
 603      gzip_proxied any;
 604      gzip_disable "msie6";
 605      gzip_static off;
 606  
 607      server_tokens off;
 608      limit_conn_zone \$binary_remote_addr zone=arbeit:10m;
 609      connection_pool_size 256;
 610      reset_timedout_connection on;
 611      ignore_invalid_headers on;
 612  
 613      include /etc/nginx/sites-enabled/*;
 614  }
 615  EOF
 616  
 617          # Generate Ronin UI reverse proxy server vhost
 618          sudo tee "/etc/nginx/sites-enabled/001-roninui" <<EOF >/dev/null
 619  server {
 620      listen 80;
 621      server_name ronindojo ${_tor_hostname};
 622  
 623      ## Access and error logs.
 624      access_log /var/log/nginx/ronindojo_access.log;
 625      error_log /var/log/nginx/ronindojo_error.log;
 626  
 627      # Prevent iframe jacking
 628      add_header X-Frame-Options "SAMEORIGIN";
 629  
 630      # Prevent clickjacking attacks
 631      add_header X-Frame-Options DENY;
 632  
 633      # Prevent "mime" based attacks
 634      add_header X-Content-Type-Options nosniff;
 635  
 636      # Prevent XSS attacks
 637      add_header X-XSS-Protection "1; mode=block";
 638  
 639      location / {
 640          proxy_http_version      1.1;
 641          proxy_set_header        Upgrade \$http_upgrade;
 642          proxy_set_header        Connection "upgrade";
 643          proxy_set_header        Host \$http_host;
 644          proxy_cache_bypass      \$http_upgrade;
 645          proxy_next_upstream     error timeout http_502 http_503 http_504;
 646          proxy_pass              http://127.0.0.1:8470;
 647          proxy_read_timeout      10m;
 648          proxy_connect_timeout   10m;
 649          proxy_send_timeout      10m;
 650          send_timeout            10m;
 651      }
 652  }
 653  EOF
 654      elif ! sudo grep -q "listen 80;" /etc/nginx/sites-enabled/001-roninui; then
 655          # Updates the ip in vhost
 656          sudo sed -i "s/listen .*$/listen 80;/" /etc/nginx/sites-enabled/001-roninui
 657  
 658          # Reload nginx server
 659      fi
 660  
 661      # Remove all defaults (some even sauses a failure for nginx.service)
 662      sudo rm -rf /etc/nginx/sites-enabled/default
 663      sudo rm -f /etc/nginx/sites-enabled/000-default
 664  
 665      # Let the service config be loaded
 666      sudo systemctl reload --quiet nginx
 667  
 668      # Enable nginx on boot
 669      if ! systemctl is-enabled --quiet nginx; then
 670          sudo systemctl enable --quiet nginx
 671      fi
 672  
 673      # (Re)Start nginx service
 674      if _is_active "$service"; then
 675          sudo systemctl stop --quiet nginx
 676      fi
 677      sudo systemctl start --quiet nginx
 678  
 679      return 0
 680  }
 681  
 682  #
 683  # Ronin UI Uninstall
 684  #
 685  _ronin_ui_uninstall() {
 686      cd "${ronin_ui_path}" || exit
 687  
 688      _print_message "Uninstalling Ronin UI..."
 689      _sleep
 690  
 691      # leave behind a marker file if this system is initialized, for any roninUI re-installs to pick up on
 692      if [ -e "${ronin_ui_path}/ronin-ui.dat" ]; then
 693          touch "${ronin_ui_init_file}"
 694      fi
 695  
 696      # Delete app from process list
 697      pm2 delete "RoninUI"
 698  
 699      # dump all processes for resurrecting them later
 700      pm2 save 1>/dev/null
 701  
 702      # Remove ${ronin_ui_path}
 703      cd "${HOME}" || exit
 704  
 705      rm -rf "${ronin_ui_path}" || exit
 706  
 707      # Remove nginx vhost and disable nginx on boot
 708      sudo rm /etc/nginx/sites-enabled/001-roninui
 709      sudo systemctl disable --now nginx
 710  
 711      # Disable avahi host and disable avahi-daemon on boot
 712      sudo rm /etc/avahi/services/http.service
 713      sudo systemctl disable --now avahi-daemon
 714  
 715      return 0
 716  }
 717  
 718  #
 719  # Returns whether this system has fan control.
 720  # For only support Rockpro64 boards.
 721  #
 722  _has_fan_control() {
 723      if grep 'rockpro64' /etc/armbian-image-release 1>/dev/null ; then
 724          # Find fan control file
 725          cd /sys/class/hwmon || exit
 726  
 727          for dir in *; do
 728              if [ -f "${dir}/pwm1" ]; then
 729                  hwmon_dir="${dir}"
 730                  return 0
 731              fi
 732          done
 733      fi
 734  
 735      return 1
 736  }
 737  
 738  #
 739  # Is fan control installed
 740  #
 741  _is_fan_control_installed() {
 742      if [ -d "${HOME}"/bitbox-base ]; then
 743          return 0
 744      fi
 745  
 746      return 1
 747  }
 748  
 749  #
 750  # Install fan control for rockchip boards
 751  #
 752  _fan_control_install() {
 753      local upgrade
 754      upgrade=false
 755  
 756      if ! _is_fan_control_installed; then
 757          git clone -q https://github.com/digitalbitbox/bitbox-base.git  || return 1
 758          cd bitbox-base/tools/bbbfancontrol || return 1
 759      else
 760          sudo systemctl stop --quiet bbbfancontrol
 761  
 762          if ! _fan_control_upgrade; then
 763              return 1
 764          fi
 765  
 766          upgrade=true
 767      fi
 768  
 769      _fan_control_compile || return 1
 770  
 771      _fan_control_unit_file || return 1
 772  
 773      _start_service_if_inactive bbbfancontrol
 774  
 775      if "${upgrade}"; then
 776          _print_message "Fan control upgraded..."
 777      else
 778          _print_message "Fan control installed..."
 779      fi
 780  
 781      return 0
 782  }
 783  
 784  #
 785  # Install fan control for rockchip boards
 786  #
 787  _fan_control_uninstall() {
 788      if _is_fan_control_installed && [ -f /etc/systemd/system/bbbfancontrol.service ]; then
 789  
 790          sudo systemctl stop --quiet bbbfancontrol
 791  
 792          sudo systemctl disable --quiet bbbfancontrol
 793  
 794          sudo rm /etc/systemd/system/bbbfancontrol.service
 795  
 796          rm -rf "${HOME}"/bitbox-base || exit
 797  
 798          _print_message "Fan control Uninstalled..."
 799      fi
 800  
 801      return 0
 802  }
 803  
 804  #
 805  # Fan Control systemd unit file
 806  #
 807  _fan_control_unit_file() {
 808      if [ ! -f /etc/systemd/system/bbbfancontrol.service ]; then
 809          sudo tee "/etc/systemd/system/bbbfancontrol.service" <<EOF >/dev/null
 810  [Unit]
 811  Description=BitBoxBase fancontrol
 812  After=local-fs.target
 813  
 814  [Service]
 815  Type=simple
 816  ExecStart=/usr/local/sbin/bbbfancontrol --tmin 60 --tmax 75 --cooldown 55 -fan /sys/class/hwmon/${hwmon_dir}/pwm1
 817  Restart=always
 818  RestartSec=10
 819  
 820  [Install]
 821  WantedBy=multi-user.target
 822  EOF
 823  
 824          sudo systemctl enable --quiet bbbfancontrol
 825          sudo systemctl start --quiet bbbfancontrol
 826      else # Previous unit file found
 827          # Update unit file if hwmon directory location changed
 828          if ! grep "${hwmon_dir}" /etc/systemd/system/bbbfancontrol.service 1>/dev/null; then
 829              sudo sed -i "s:/sys/class/hwmon/hwmon[0-9]/pwm1:/sys/class/hwmon/${hwmon_dir}/pwm1:" /etc/systemd/system/bbbfancontrol.service
 830  
 831              # Reload systemd unit file & restart daemon
 832              sudo systemctl daemon-reload
 833              sudo systemctl restart --quiet bbbfancontrol.service
 834          fi
 835      fi
 836  
 837      return 0
 838  }
 839  
 840  #
 841  # Fan Control build package
 842  #
 843  _fan_control_compile() {
 844      # Build package
 845      go build || return 1
 846  
 847      sudo cp bbbfancontrol /usr/local/sbin/
 848  
 849      return 0
 850  }
 851  
 852  #
 853  # Update fan control for rockchip boards
 854  #
 855  _fan_control_upgrade() {
 856      cd "${HOME}"/bitbox-base || exit
 857  
 858      if (($(git pull --rebase|wc -l)>1)); then
 859          cd tools/bbbfancontrol || return 1
 860          return 0
 861      else
 862          return 1
 863      fi
 864  }
 865  
 866  _set_addrindexrs() {
 867      sudo sed -i 's/INDEXER_INSTALL=.*$/INDEXER_INSTALL=on/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 868      sudo sed -i 's/INDEXER_TYPE=.*$/INDEXER_TYPE=addrindexrs/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 869      sudo sed -i 's/NODE_ACTIVE_INDEXER=.*$/NODE_ACTIVE_INDEXER=local_indexer/' "${dojo_path_my_dojo}"/conf/docker-node.conf
 870      sudo sed -i 's/INDEXER_BATCH_SUPPORT=.*$/INDEXER_BATCH_SUPPORT=inactive/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 871      sudo sed -i 's/INDEXER_EXTERNAL=.*$/INDEXER_EXTERNAL=off/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 872  
 873      return 0
 874  }
 875  
 876  _set_fulcrum() {
 877      sudo sed -i 's/INDEXER_INSTALL=.*$/INDEXER_INSTALL=on/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 878      sudo sed -i 's/INDEXER_TYPE=.*$/INDEXER_TYPE=fulcrum/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 879      sudo sed -i 's/NODE_ACTIVE_INDEXER=.*$/NODE_ACTIVE_INDEXER=local_indexer/' "${dojo_path_my_dojo}"/conf/docker-node.conf
 880      sudo sed -i 's/INDEXER_BATCH_SUPPORT=.*$/INDEXER_BATCH_SUPPORT=active/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 881      sudo sed -i 's/INDEXER_EXTERNAL=.*$/INDEXER_EXTERNAL=on/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 882  
 883      return 0
 884  }
 885  
 886  _set_electrs() {
 887      sudo sed -i 's/INDEXER_INSTALL=.*$/INDEXER_INSTALL=on/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 888      sudo sed -i 's/INDEXER_TYPE=.*$/INDEXER_TYPE=electrs/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 889      sudo sed -i 's/NODE_ACTIVE_INDEXER=.*$/NODE_ACTIVE_INDEXER=local_indexer/' "${dojo_path_my_dojo}"/conf/docker-node.conf
 890      sudo sed -i 's/INDEXER_BATCH_SUPPORT=.*$/INDEXER_BATCH_SUPPORT=inactive/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 891      sudo sed -i 's/INDEXER_EXTERNAL=.*$/INDEXER_EXTERNAL=off/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 892  
 893      return 0
 894  }
 895  
 896  _set_no_indexer() {
 897      sudo sed -i 's/INDEXER_INSTALL=.*$/INDEXER_INSTALL=off/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 898      sudo sed -i 's/INDEXER_TYPE=.*$/INDEXER_TYPE=electrs/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 899      sudo sed -i 's/NODE_ACTIVE_INDEXER=.*$/NODE_ACTIVE_INDEXER=local_bitcoind/' "${dojo_path_my_dojo}"/conf/docker-node.conf
 900      sudo sed -i 's/INDEXER_EXTERNAL=.*$/INDEXER_EXTERNAL=off/' "${dojo_path_my_dojo}"/conf/docker-indexer.conf
 901  
 902      return 0
 903  }
 904  
 905  #
 906  # Checks what indexer is set if any
 907  #
 908  _fetch_configured_indexer_type() {
 909      # shellcheck disable=SC2154 
 910      if [ "local_indexer" != "$(source ${dojo_path_my_dojo}"/conf/docker-node.conf"; echo "${NODE_ACTIVE_INDEXER}")" ]; then
 911          return 3
 912          # No indexer
 913      elif [ "on" != "$(source ${dojo_path_my_dojo}"/conf/docker-indexer.conf"; echo "${INDEXER_INSTALL}")" ]; then
 914          return 3
 915          # No indexer
 916      elif _is_electrs; then
 917          return 0
 918          # Found electrs
 919      elif _is_addrindexrs; then
 920          return 1
 921          # Found SW indexer
 922      elif _is_fulcrum; then
 923          return 2
 924          # Found fulcrum
 925      fi
 926  }
 927  
 928  #
 929  # Offer user choice of indexer
 930  #
 931  _indexer_prompt() {
 932      # shellcheck source=./Scripts/defaults.sh
 933      . "${HOME}"/RoninDojo/Scripts/defaults.sh
 934  
 935      _print_message "Preparing the Indexer Prompt..."
 936      _sleep 3
 937  
 938      _print_message "Samourai Indexer is only recommended for light wallet use. Do not use if you have a high adress index value..."
 939      _sleep 3
 940  
 941      _print_message "Fulcrum Server is recommended for Wallets with heavy use, Hardware Wallets, Multisig, and other Electrum features..."
 942      _sleep 1
 943      _print_message "Fulcrum has a longer indexer time than Electrs, but much more robust for heavier wallets..."
 944      _sleep 3
 945  
 946      _print_message "Electrs is recommended for Hardware Wallets, Multisig, and other Electrum features..."
 947      _sleep 1
 948      _print_message "Electrs has a faster indexer time than Fulcrum, but less reliable for heavier wallets..."
 949      _sleep 3
 950  
 951      _print_message "Choose one of the following options for your Indexer..."
 952      _sleep
 953  
 954      while true; do
 955          select indexer in "Samourai Indexer" "Fulcrum" "Electrs"; do
 956              case $indexer in
 957                  "Samourai Indexer")
 958                      _print_message "Selected Samourai Indexer..."
 959                      _sleep
 960                      _set_addrindexrs
 961                      return
 962                      ;;
 963                  "Fulcrum")
 964                      _print_message "Selected Fulcrum..."
 965                      _sleep
 966                      _set_fulcrum
 967                      return
 968                      ;;
 969                  "Electrs")
 970                      _print_message "Selected Electrs..."
 971                      _sleep
 972                      _set_electrs
 973                      return
 974                      ;;
 975                  *)
 976                      _print_message "Invalid Entry! Valid values are 1, 2, or 3..."
 977                      _sleep
 978                      break
 979                      ;;
 980              esac
 981          done
 982      done
 983      exit 1
 984  }
 985  
 986  #
 987  # Check if dojo directory is missing
 988  #
 989  _is_dojo() {
 990      local menu
 991      menu="$1"
 992  
 993      if [ ! -d "${dojo_path}" ]; then
 994          _print_message "Missing ${dojo_path} directory!"
 995          _pause return
 996          bash -c "$menu"
 997          exit 1
 998  fi
 999  }
1000  
1001  #
1002  # Check if mempool enabled
1003  #
1004  _is_mempool() {
1005      if grep "MEMPOOL_INSTALL=off" "${dojo_path_my_dojo}"/conf/docker-mempool.conf 1>/dev/null; then
1006          return 1
1007      else
1008          return 0
1009      fi
1010  }
1011  
1012  #
1013  # Uninstall Mempool Space Visualizer
1014  #
1015  _mempool_uninstall() {
1016      # shellcheck source=./Scripts/dojo-defaults.sh
1017      . "${HOME}"/RoninDojo/Scripts/dojo-defaults.sh
1018  
1019      _print_message "Uninstalling Mempool Space Visualizer ${_mempool_version}..."
1020      sed -i 's/MEMPOOL_INSTALL=.*$/MEMPOOL_INSTALL=off/' "$dojo_path_my_dojo"/conf/docker-mempool.conf
1021      # Turns mempool install set to off
1022  
1023      _print_message "Mempool Space Visualizer ${_mempool_version} Uninstalled..."
1024      return 0
1025  }
1026  
1027  #
1028  # Setup mempool docker variables
1029  #
1030  _mempool_conf() {
1031      if ! grep -q 'MYSQL_USER=mempool' "${dojo_path_my_dojo}"/conf/docker-mempool.conf; then # Existing install
1032          MEMPOOL_MYSQL_USER=$(grep MYSQL_USER "${dojo_path_my_dojo}"/conf/docker-mempool.conf | cut -d '=' -f2)
1033          MEMPOOL_MYSQL_PASS=$(grep MYSQL_PASS "${dojo_path_my_dojo}"/conf/docker-mempool.conf | cut -d '=' -f2)
1034          MEMPOOL_MYSQL_ROOT_PASSWORD=$(grep MYSQL_ROOT_PASSWORD "${dojo_path_my_dojo}"/conf/docker-mempool.conf | cut -d '=' -f2)
1035      else
1036          # Generate mempool MySQL credentials for a fresh install
1037          # shellcheck source=./Scripts/generated-credentials.sh
1038          . "${HOME}"/RoninDojo/Scripts/generated-credentials.sh
1039      fi
1040  
1041      # source values for docker-bitcoind.conf
1042      . "${dojo_path_my_dojo}"/conf/docker-bitcoind.conf
1043  
1044      _load_user_conf
1045  
1046      # Enable mempool and set MySQL credentials
1047      sed -i -e 's/MEMPOOL_INSTALL=.*$/MEMPOOL_INSTALL=on/' \
1048      -e "s/MEMPOOL_MYSQL_USER=.*$/MEMPOOL_MYSQL_USER=${MEMPOOL_MYSQL_USER}/" \
1049      -e "s/MEMPOOL_MYSQL_PASS=.*$/MEMPOOL_MYSQL_PASS=${MEMPOOL_MYSQL_PASS}/" \
1050      -e "s/MEMPOOL_MYSQL_ROOT_PASSWORD=.*$/MEMPOOL_MYSQL_ROOT_PASSWORD=${MEMPOOL_MYSQL_ROOT_PASSWORD}/" "${dojo_path_my_dojo}"/conf/docker-mempool.conf
1051  }
1052  
1053  #
1054  # Update Samourai Dojo Repository
1055  #
1056  _dojo_update() {
1057      _load_user_conf
1058  
1059      cd "${dojo_path}" || exit
1060  
1061      git fetch -q --tags --force
1062      git checkout -q -f "${samourai_commitish}"
1063  
1064      _print_message "Dojo codebase updated!"
1065  }
1066  
1067  #
1068  # Upgrade Samourai Dojo
1069  #
1070  _dojo_upgrade() {
1071      _print_message "Performing Dojo upgrade"
1072      _stop_dojo
1073  
1074      . dojo.sh upgrade --nolog --auto
1075  
1076      # get rid of orphan volumes
1077      if [ "${1}" = "prune" ]; then
1078          docker volume prune -f
1079      fi
1080  
1081      _pause return
1082  }
1083  
1084  #
1085  # Asserts dojo to be installed
1086  #
1087  _assert_dojo_is_installed() {
1088      _load_user_conf
1089  
1090      if ! findmnt "${install_dir}" 1>/dev/null; then
1091          _print_error_message "Missing drive mount at ${install_dir}!"
1092          _print_error_message "Please contact support for assistance..."
1093          _pause exit
1094          exit
1095      fi
1096  
1097      if ! _is_active docker; then
1098          _print_error_message "Expected docker to be running, but it wasn't!"
1099          _print_error_message "Please contact support for assistance..."
1100          _pause exit
1101          exit
1102      fi
1103  
1104      if [ ! -d "${dojo_path}" ]; then
1105          _print_error_message "Expected dojo to be installed, but it wasn't!"
1106          _print_error_message "Please contact support for assistance..."
1107          _pause exit
1108          exit
1109      fi
1110  }
1111  
1112  #
1113  # Returns whether or not dojo is running
1114  #
1115  _is_dojo_running() {
1116      if [ "$(docker inspect --format='{{.State.Running}}' db 2>/dev/null)" = "true" ]; then
1117          return 0
1118      fi
1119  
1120      return 1
1121  }
1122  
1123  #
1124  # Source DOJO confs
1125  #
1126  _source_dojo_conf() {
1127      for conf in conf/docker-{indexer,bitcoind,explorer,mempool}.conf .env; do
1128          test -f "${conf}" && . "${conf}"
1129      done
1130  
1131      export BITCOIND_RPC_EXTERNAL_IP INDEXER_RPC_PORT BITCOIND_RPC_USER BITCOIND_RPC_PASSWORD BITCOIND_RPC_PORT
1132  }
1133  
1134  #
1135  # Stop Samourai Dojo containers
1136  #
1137  _stop_dojo() {
1138  
1139      _assert_dojo_is_installed
1140  
1141      _print_message "Shutting down Dojo..."
1142  
1143      cd "${dojo_path_my_dojo}" || exit
1144      ./dojo.sh stop
1145  
1146      return 0
1147  }
1148  
1149  #
1150  # Start Samourai Dojo containers
1151  #
1152  _start_dojo() {
1153  
1154      _assert_dojo_is_installed
1155  
1156      _print_message "Starting Dojo..."
1157      _sleep
1158  
1159      cd "${dojo_path_my_dojo}" || exit 1
1160      ./dojo.sh start
1161  
1162      return 0
1163  }
1164  
1165  #
1166  # Update RoninDojo
1167  #
1168  _ronindojo_update() {
1169      _load_user_conf
1170  
1171      cd "${HOME}/RoninDojo" || exit
1172  
1173      # Fetch remotes
1174      git fetch -q --tags --force
1175      git checkout -q -f "${ronin_dojo_branch}"
1176  }
1177  
1178  #
1179  # Check if Docker is installed
1180  #
1181  _install_docker_if_not_present() {
1182      if ! command -v docker &> /dev/null; then
1183          _install_docker
1184      else
1185          echo "Docker is already installed."
1186      fi
1187  }
1188  
1189  
1190  #
1191  # Docker install Debian Docker
1192  #
1193  _install_docker() {
1194      if [ ! -d /etc/apt/keyrings ]; then
1195          sudo mkdir -m 0755 -p /etc/apt/keyrings
1196      fi
1197      sudo curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
1198      sudo echo \
1199      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
1200      $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
1201      sudo apt-get update
1202      sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
1203  }
1204  
1205  #
1206  # Check if Docker is installed
1207  #
1208  _install_docker_compose_if_not_present() {
1209      if ! command -v docker-compose &> /dev/null; then
1210          _install_docker_compose
1211      else
1212          echo "Docker is already installed."
1213      fi
1214  }
1215  
1216  #
1217  # Docker install Debian Docker
1218  #
1219  _install_docker_compose() {
1220      sudo curl -L https://github.com/docker/compose/releases/download/v2.0.1/docker-compose-linux-aarch64 -o /usr/bin/docker-compose
1221      sudo chmod +x /usr/bin/docker-compose
1222  }
1223  
1224  
1225  #
1226  # Docker Data Directory
1227  #
1228  _docker_datadir_setup() {
1229      _load_user_conf
1230  
1231      _install_docker_if_not_present
1232      _install_docker_compose_if_not_present
1233      _print_message "Now configuring docker to use the external SSD..."
1234      test -d "${install_dir_docker}" || sudo mkdir "${install_dir_docker}"
1235      # makes directory to store docker/dojo data
1236  
1237      if [ -d /etc/docker ]; then
1238          _print_message "The /etc/docker directory already exists..."
1239      else
1240          _print_message "Creating /etc/docker directory."
1241          sudo mkdir /etc/docker
1242          # makes docker directory
1243      fi
1244  
1245      # We can skip this if daemon.json was previous created
1246      if [ ! -f /etc/docker/daemon.json ]; then
1247          sudo tee "/etc/docker/daemon.json" << EOF > /dev/null
1248  {
1249    "log-driver": "json-file",
1250    "log-opts": {
1251      "max-size": "10m",
1252      "max-file": "3"
1253    },
1254    "data-root": "${install_dir_docker}"
1255  }
1256  EOF
1257  
1258          _print_message "Starting docker daemon."
1259      fi
1260  
1261      _start_service_if_inactive docker
1262  
1263      # Enable service on startup
1264      if ! sudo systemctl is-enabled --quiet docker; then
1265          sudo systemctl enable --quiet docker
1266      fi
1267  
1268      # Make sure ronindojo user is part of docker group
1269      sudo usermod -aG docker "$USER"
1270  
1271      return 0
1272  }
1273  
1274  #
1275  # Disable ipv6
1276  #
1277  _disable_ipv6() {
1278      if [ -f /boot/cmdline.txt ]; then
1279          if grep ipv6.disable /boot/cmdline.txt 1>/dev/null; then
1280              sudo sed -i 's/ipv6.disable=1//' /boot/cmdline.txt
1281              return 1
1282          fi
1283          # for RPI hardware
1284      elif [ -f /boot/boot.ini ]; then
1285          if grep ipv6.disable /boot/boot.ini 1>/dev/null; then
1286              sudo sed -i 's/ipv6.disable=1//' /boot/boot.ini
1287              return 1
1288          fi
1289          # for Odroid or RockPro64 hardware
1290      fi
1291  
1292      if [ ! -f /etc/sysctl.d/40-ipv6.conf ]; then
1293          sudo tee "/etc/sysctl.d/40-ipv6.conf" <<EOF >/dev/null
1294  # Disable IPV6
1295  net.ipv6.conf.all.disable_ipv6 = 1
1296  EOF
1297      else
1298          return 1
1299      fi
1300  
1301      # Check to see if ipv6 stack available and if so
1302      # restart sysctl service
1303      if [ -d /proc/sys/net/ipv6 ]; then
1304          sudo systemctl restart --quiet systemd-sysctl
1305      fi
1306  
1307      return 0
1308  }
1309  
1310  #
1311  # Disable Bluetooth
1312  #
1313  _disable_bluetooth() {
1314      _systemd_unit_exist bluetooth || return 1
1315  
1316      if _is_active bluetooth; then
1317          sudo systemctl --quiet disable bluetooth
1318          sudo systemctl stop --quiet bluetooth
1319          return 0
1320      fi
1321  }
1322  
1323  #
1324  # Makes sure we don't already have swapfile enabled
1325  #
1326  check_swap() {
1327      local swapfile
1328      swapfile="$1"
1329  
1330      if ! grep "$swapfile" /proc/swaps 1>/dev/null; then # no swap currently
1331          return 1
1332      fi
1333  
1334      return 0
1335  }
1336  
1337  #
1338  # Returns RAM total or a percentage of it
1339  #
1340  _mem_total() {
1341      local t
1342      t=false
1343  
1344      _load_user_conf
1345  
1346      # Parse Arguments
1347      while [ $# -gt 0 ]; do
1348          case "$1" in
1349              --total|-t)
1350                  t=true
1351                  shift 1
1352                  ;;
1353              [0-9].[0-9])
1354                  num=$1
1355                  shift
1356                  ;;
1357          esac
1358      done
1359  
1360      if "${t}"; then
1361          # returns total
1362          awk '/MemTotal/ {printf("%d\n", $2 / 1024)}' /proc/meminfo
1363      else
1364          # returns percentage
1365          awk -vn="$num" '/MemTotal/ {printf("%d\n", $2 / 1024 * n )}' /proc/meminfo
1366      fi
1367  }
1368  
1369  #
1370  # Calculate swapfile size based on available RAM
1371  #
1372  _swap_size() {
1373      # Calculate swap file size when swapfile_size variable is not set
1374      _size="${swapfile_size:-$(_mem_total -t)}"
1375  
1376      for num in 1024 2096; do
1377          if [ -z "${swapfile_size}" ]; then
1378              # < 2GB set twice RAM total for swapfile
1379              if (( num >= 0 && _size <= num )); then
1380                  _size=$((_size * 2))
1381                  break
1382              fi
1383  
1384              # > 2GB, use same amount for swapfile
1385              if (( num >= 2096 && num <= _size )); then
1386                  break
1387              fi
1388          fi
1389      done
1390  }
1391  
1392  #
1393  # Creates a swap
1394  # TODO enable multiple swapfiles/partitions
1395  #
1396  create_swap() {
1397      # Parse Arguments
1398      while [ $# -gt 0 ]; do
1399          case "$1" in
1400              --file|-f)
1401                  file=${2}
1402                  shift 2
1403                  ;;
1404              --count|-c)
1405                  count=${2}
1406                  shift 2
1407                  ;;
1408              *) # unsupported flags
1409                  echo "Error: Unsupported flag $1" >&2
1410                  exit 1
1411                  ;;
1412          esac
1413      done
1414  
1415      if ! check_swap "${file}"; then
1416          _print_message "Creating swapfile..."
1417  
1418          sudo dd if=/dev/zero of="${file}" bs=1M count="${count}" 2>/dev/null
1419          sudo chmod 600 "${file}"
1420          sudo mkswap -p 0 "${file}" 1>/dev/null
1421          sudo swapon "${file}"
1422      else
1423          _print_message "Swapfile already created..."
1424      fi
1425  
1426      # Include fstab value
1427      if ! grep "${file}" /etc/fstab 1>/dev/null; then
1428          _print_message "Creating swapfile entry in /etc/fstab"
1429          sudo bash -c "cat <<EOF >>/etc/fstab
1430  ${file} swap swap defaults,pri=0 0 0
1431  EOF"
1432      fi
1433  }
1434  
1435  #
1436  # Whirlpool Stats Tool
1437  #
1438  _install_wst(){
1439      cd "${HOME}" || exit
1440  
1441      git clone -q "${whirlpool_stats_repo}" Whirlpool-Stats-Tool 2>/dev/null
1442  
1443      _install_pkg_if_missing "pipenv"
1444  
1445      cd Whirlpool-Stats-Tool || exit
1446  
1447      pip install setuptools
1448      pipenv install -r requirements.txt
1449  }
1450  
1451  #
1452  # Boltzmann Entropy Calculator
1453  #
1454  _install_boltzmann(){
1455      cd "${HOME}" || exit
1456  
1457      git clone -q "$boltzmann_repo"
1458  
1459      cd boltzmann || exit
1460      # Pull Boltzmann
1461  
1462      _print_message "Checking package dependencies..."
1463  
1464      # Check for package dependency
1465      _install_pkg_if_missing "pipenv"
1466  
1467      # Setup a virtual environment to hold boltzmann dependencies. We should use this
1468      # with all future packages that ship a requirements.txt.
1469      pip install setuptools
1470      pipenv install -r requirements.txt
1471  }
1472  
1473  #
1474  # Indexer data restore
1475  #
1476  _dojo_data_indexer_restore() {
1477      _load_user_conf
1478  
1479      if sudo test -d "${dojo_backup_electrs}"/_data && sudo test -d "${docker_volume_electrs}"/_data; then
1480          _print_message "Electrs data restore starting..."
1481  
1482          sudo rm -rf "${docker_volume_electrs}"/_data
1483          sudo mv "${dojo_backup_electrs}"/_data "${docker_volume_electrs}"/
1484          sudo rm -rf "${dojo_backup_electrs}"
1485  
1486          _print_message "Electrs data restore completed..."
1487  
1488      elif sudo test -d "${dojo_backup_indexer}"/_data && sudo test -d "${docker_volume_indexer}"/_data; then
1489          _print_message "Addrindexrs data restore starting..."
1490  
1491          sudo rm -rf "${docker_volume_indexer}"/_data
1492          sudo mv "${dojo_backup_indexer}"/_data "${docker_volume_indexer}"/
1493          sudo rm -rf "${dojo_backup_indexer}"
1494  
1495          _print_message "Addrindexrs data restore completed..."
1496  
1497      elif sudo test -d "${dojo_backup_fulcrum}"/_data && sudo test -d "${docker_volume_fulcrum}"/_data; then
1498          _print_message "Fulcrum data restore starting..."
1499  
1500          sudo rm -rf "${docker_volume_fulcrum}"/_data
1501          sudo mv "${dojo_backup_fulcrum}"/_data "${docker_volume_fulcrum}"/
1502          sudo rm -rf "${dojo_backup_fulcrum}"
1503  
1504          _print_message "Fulcrum data restore completed..."
1505  
1506      fi
1507  }
1508  
1509  #
1510  # Indexer data backup
1511  #
1512  _dojo_data_indexer_backup() {
1513      _load_user_conf
1514      
1515      if sudo test -d "${backup_mount}/${indexer_data_dir}/_data/addrindexrs"; then # Addrindexrs
1516  
1517          _print_message "Found Addrindexrs data for salvage!"
1518          _print_message "Moving to data backup"
1519  
1520          test -d "${indexer_backup_dir}" || sudo mkdir -p "${indexer_backup_dir}"
1521          sudo mv -v "${backup_mount}/${indexer_data_dir}/_data" "${indexer_backup_dir}"/
1522  
1523          _print_message "Addrindexrs data prepared for salvage!"
1524  
1525      elif sudo test -d "${backup_mount}/${electrs_data_dir}/_data"; then # Electrs
1526  
1527          _print_message "Found Electrs data for salvage!"
1528          _print_message "Moving to data backup"
1529  
1530          test -d "${electrs_backup_dir}" || sudo mkdir -p "${electrs_backup_dir}"
1531          sudo mv -v "${backup_mount}/${electrs_data_dir}/_data" "${electrs_backup_dir}"/
1532  
1533          _print_message "Electrs data prepared for salvage!"
1534  
1535      elif sudo test -d "${backup_mount}/${fulcrum_data_dir}/_data"; then # Fulcrum
1536  
1537          _print_message "Found Fulcrum data for salvage!"
1538          _print_message "Moving to data backup"
1539          
1540          test -d "${fulcrum_backup_dir}" || sudo mkdir -p "${fulcrum_backup_dir}"
1541          sudo mv -v "${backup_mount}/${fulcrum_data_dir}/_data" "${fulcrum_backup_dir}"/
1542  
1543          _print_message "Fulcrum data prepared for salvage!"
1544      fi
1545  }
1546  
1547  #
1548  # Bitcoin IBD restore
1549  #
1550  _dojo_data_bitcoind_restore() {
1551      _load_user_conf
1552  
1553      if sudo test -d "${dojo_backup_bitcoind}/blocks" && sudo test -d "${docker_volume_bitcoind}"; then
1554          _print_message "Blockchain data restore starting..."
1555  
1556          for dir in blocks chainstate indexes; do
1557              if sudo test -d "${docker_volume_bitcoind}"/_data/"${dir}"; then
1558                  sudo rm -rf "${docker_volume_bitcoind}"/_data/"${dir}"
1559              fi
1560          done
1561  
1562          for dir in blocks chainstate indexes; do
1563              if sudo test -d "${dojo_backup_bitcoind}"/"${dir}"; then
1564                  sudo mv "${dojo_backup_bitcoind}"/"${dir}" "${docker_volume_bitcoind}"/_data/
1565              fi
1566          done
1567  
1568          _print_message "Blockchain data restore completed..."
1569          sudo rm -rf "${dojo_backup_bitcoind}"
1570      fi
1571  }
1572  
1573  #
1574  # Bitcoin IBD backup
1575  #
1576  _dojo_data_bitcoind_backup() {
1577      _load_user_conf
1578  
1579      if sudo test -d "${backup_mount}/${bitcoind_data_dir}/_data/blocks"; then #bitcoind
1580          _print_message "Found Blockchain data for salvage!"
1581          _print_message "Moving to data backup"
1582          test -d "${bitcoin_ibd_backup_dir}" || sudo mkdir -p "${bitcoin_ibd_backup_dir}"
1583  
1584          sudo mv -v "${backup_mount}/${bitcoind_data_dir}/_data/"{blocks,chainstate,indexes} "${bitcoin_ibd_backup_dir}"/
1585  
1586          _print_message "Blockchain data prepared for salvage!"
1587      fi
1588  }
1589  
1590  #
1591  # Tor credentials backup
1592  #
1593  _tor_backup() {
1594      _load_user_conf
1595  
1596      if sudo test -d "${backup_mount}/${tor_data_dir}/_data/hsv3dojo"; then # tor
1597  
1598          _print_message "Found Tor data for salvage!"
1599          _print_message "Moving to data backup"
1600          test -d "${tor_backup_dir}" || sudo mkdir -p "${tor_backup_dir}"
1601  
1602          sudo bash -c "mv -v ${backup_mount}/${tor_data_dir}/_data/hsv3* ${tor_backup_dir}/"
1603  
1604          _print_message "Tor data prepared for salvage!"
1605      fi
1606  }
1607  
1608  #
1609  # Tor credentials restore
1610  #
1611  _tor_restore() {
1612      _load_user_conf
1613  
1614      if sudo test -d "${dojo_backup_tor}"/hsv3dojo; then
1615          _print_message "Tor data restore starting..."
1616  
1617          sudo bash -c "rm -rf ${install_dir}/${tor_data_dir}/_data/*"
1618          sudo bash -c "mv -v ${dojo_backup_tor}/* ${install_dir}/${tor_data_dir}/_data"
1619  
1620          _print_message "Tor data restore completed..."
1621          sudo rm -rf "${dojo_backup_tor}"
1622      fi
1623  }
1624  
1625  #
1626  # Yes or No Prompt
1627  #
1628  _yes_or_no() {
1629      while true; do
1630          read -rp "$* ${green}[y/n]:${nc} " yn
1631          case $yn in
1632              [Yy]*) return 0;;
1633              [Nn]*) return 1;;
1634          esac
1635      done
1636  }
1637  
1638  #
1639  # SSH Key Management
1640  #
1641  _ssh_key_authentication() {
1642      local _add_ssh_key=false _del_ssh_key=false _pub_ssh_key_path=/tmp/pub-ssh-key
1643  
1644      # Parse Arguments
1645      while [ $# -gt 0 ]; do
1646          case "$1" in
1647              add-ssh-key)
1648                  _add_ssh_key=true
1649                  break
1650                  ;;
1651              del-ssh-key)
1652                  _del_ssh_key=true
1653                  break
1654                  ;;
1655              enable)
1656                  if sudo grep -q "UsePAM no" /etc/ssh/sshd_config; then
1657                      printf "%s\n***\nSSH Key Authentication already enabled! Returning to menu...\n***%s\n" "${red}" "${nc}"
1658  
1659                      return 1
1660                  else
1661                      printf "%s\n***\nThis will enable SSH key authentication ONLY and will disable password authentication...\n***%s\n\n" "${red}" "${nc}"
1662  
1663                      if _yes_or_no "Do you wish to continue?"; then
1664                          printf "%s\n***\nGenerating sshd configuration file...\n***%s\n" "${red}" "${nc}"
1665  
1666                          # Backup original sshd_config
1667                          sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config_original
1668  
1669                          sudo bash -c "cat <<EOF >/etc/ssh/sshd_config
1670  PasswordAuthentication no
1671  PermitEmptyPasswords no
1672  UsePAM no
1673  AllowUsers $USER
1674  EOF
1675  "
1676                          printf "%s\n***\nRestarting SSH daemon...\n***%s\n\n" "${red}" "${nc}"
1677                          sudo systemctl restart --quiet sshd
1678                      else
1679                          return 1
1680                      fi
1681  
1682                      return 0
1683                  fi
1684                  ;;
1685              disable)
1686                  if sudo grep -q "UsePAM no" /etc/ssh/sshd_config; then
1687                      printf "%s\n***\nRestoring sshd_config to defaults...\n***%s\n" "${red}" "${nc}"
1688                      sudo cp /etc/ssh/sshd_config_original /etc/ssh/sshd_config
1689  
1690                      printf "%s\n***\nDeleting $HOME/.ssh directory containing keys...\n***%s\n" "${red}" "${nc}"
1691                      rm -rf "${HOME}"/.ssh || exit
1692  
1693                      # Restart sshd
1694                      sudo systemctl restart --quiet sshd
1695  
1696                      return 0
1697                  else
1698                      printf "%s\n***\nSSH Key Authentication not enabled! Returning to menu...\n***%s\n" "${red}" "${nc}"
1699                      return 1
1700                  fi
1701                  ;;
1702          esac
1703      done
1704  
1705      read -rp "${red}Paste a valid SSH public key: ${nc}" _pub_ssh_key
1706  
1707      # Create a temporaly file with pasta contents
1708      echo "${_pub_ssh_key}">"${_pub_ssh_key_path}"
1709  
1710      # Verify key
1711      if ssh-keygen -lf "${_pub_ssh_key_path}" 1>/dev/null; then
1712          test -d "${HOME}"/.ssh || mkdir "${HOME}"/.ssh
1713  
1714          # Adding to authorized_keys & removing temporaly file
1715          if [ -f "${HOME}"/.ssh/authorized_keys ]; then
1716              if grep -q "${_pub_ssh_key}" "${HOME}"/.ssh/authorized_keys; then
1717                  if ${_add_ssh_key}; then
1718                      # Key already found
1719                      printf "%s\n***\nSSH public key already found. Returning to menu...\n***%s\n" "${red}" "${nc}"
1720                      return 1
1721                  elif ${_del_ssh_key}; then
1722                      # Delete key
1723                      sed -i "/${_pub_ssh_key}/d" "${HOME}"/.ssh/authorized_keys
1724                      return 0
1725                  fi
1726              else
1727                  # Adding new key
1728                  echo "${_pub_ssh_key}" >>"${HOME}"/.ssh/authorized_keys
1729  
1730                  # Shred temporaly key
1731                  shred -uzfs 42 "${_pub_ssh_key_path}"
1732  
1733                  # Unset variable
1734                  unset _pub_ssh_key_path
1735  
1736                  return 0
1737              fi
1738          else
1739              if ${_del_ssh_key}; then
1740                  # No key found to delete
1741                  return 1
1742              elif ${_add_ssh_key}; then
1743                  # Adding new key
1744                  echo "${_pub_ssh_key}" >>"${HOME}"/.ssh/authorized_keys
1745  
1746                  # Shred temporaly key
1747                  shred -uzfs 42 "${_pub_ssh_key_path}"
1748  
1749                  # Unset variable
1750                  unset _pub_ssh_key_path
1751  
1752                  return 0
1753              fi
1754          fi
1755      else
1756          printf "%s\n***\nInvalid SSH public key!\n***\n\n***Example SSH public key below...\n***%s\n" "${red}" "${nc}"
1757  
1758          printf "\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJuh9yEnlKJT1A/MijVQm2fFxoxlX3Bb1JXSUMwOX9E/ likewhoa@localhost\n"
1759  
1760          printf "%s\n***\nReturning to menu...\n***%s\n" "${red}" "${nc}"
1761  
1762          return 1
1763      fi
1764  }
1765  
1766  #
1767  # returns true/false on whether the host has a gpio system
1768  #
1769  _is_gpio_sytem() {
1770      if [ -d /sys/class/gpio ]; then
1771          return 0;
1772      else
1773          return 1;
1774      fi
1775  }
1776  
1777  #
1778  # deletes and repopulates the GPIO dir
1779  #
1780  _prepare_GPIO_datadir() {
1781      _load_user_conf
1782  
1783      _remove_GPIO_datadir
1784  
1785      git clone https://github.com/Angoosh/RockPro64-RP64.GPIO.git "${ronin_gpio_data_dir}"
1786      cp "${ronin_gpio_dir}/turn.LED.off.py" "${ronin_gpio_data_dir}"
1787      cp "${ronin_gpio_dir}/turn.LED.on.py" "${ronin_gpio_data_dir}"
1788  }
1789  
1790  #
1791  # installs the gpio service file for systemd
1792  #
1793  _install_gpio_service() {
1794      _load_user_conf
1795  
1796      _uninstall_gpio_service
1797  
1798      sudo bash -c "cat <<EOF > /etc/systemd/system/ronin.gpio.service
1799  [Unit]
1800  Description=GPIO
1801  After=multi-user.target
1802  
1803  [Service]
1804  User=root
1805  Type=oneshot
1806  RemainAfterExit=yes
1807  ExecStart=/bin/python3 ${ronin_gpio_data_dir}/turn.LED.on.py
1808  ExecStop=/bin/python3 ${ronin_gpio_data_dir}/turn.LED.off.py
1809  WorkingDirectory=${ronin_gpio_data_dir}
1810  Restart=on-failure
1811  RestartSec=30
1812  
1813  [Install]
1814  WantedBy=multi-user.target
1815  EOF
1816  "
1817  
1818      sudo systemctl daemon-reload
1819      sudo systemctl enable --now --quiet ronin.gpio
1820  }
1821  
1822  #
1823  # installs the whole gpio setup
1824  #
1825  _install_gpio() {
1826  
1827      _is_gpio_sytem
1828  
1829      if [ $? = 1 ]; then
1830          return 0
1831      fi
1832  
1833      _prepare_GPIO_datadir
1834      _install_gpio_service
1835  }
1836  
1837  _remove_GPIO_datadir() {
1838      _load_user_conf
1839  
1840      if [ -d "${ronin_gpio_data_dir}" ]; then
1841          sudo rm -rf "${ronin_gpio_data_dir}"
1842      fi
1843  }
1844  
1845  #
1846  # uninstalls the gpio service file for systemd
1847  #
1848  _uninstall_gpio_service() {
1849  
1850      if [ ! -f /etc/systemd/system/ronin.gpio.service ] && ! sudo systemctl is-active ronin.gpio; then
1851          return 0
1852      fi
1853  
1854      sudo systemctl stop ronin.gpio
1855      sudo rm -f /etc/systemd/system/ronin.gpio.service
1856      sudo systemctl daemon-reload
1857  }
1858  
1859  #
1860  # uninstalls the whole gpio setup
1861  #
1862  _uninstall_gpio() {
1863      _remove_GPIO_datadir
1864      _uninstall_gpio_service
1865  }
1866  
1867  #
1868  # Set storage config in ronin's data folder.
1869  # Current pitfalls:
1870  # - having installed with sda1 as install_dir and then adding an nvme
1871  # - having installed with nvme0n1p1 as install_dir and then adding multiple sd, the supposed backup device not being sda
1872  # - having installed with sda1 as install_dir and then adding multiple sd, the supposed backup device not being sdb
1873  #
1874  _setup_storage_config() {
1875  
1876      local blockdata_storage_partition backup_storage_partition
1877  
1878      if test -b /dev/nvme0n1; then
1879          blockdata_storage_partition="/dev/nvme0n1p1"
1880          if test -b /dev/sda; then
1881              backup_storage_partition="/dev/sda1"
1882          fi
1883      elif test -b /dev/sda; then
1884          blockdata_storage_partition="/dev/sda1"
1885          if test -b /dev/sdb; then
1886              backup_storage_partition="/dev/sdb1"
1887          fi
1888      else
1889          return 1
1890      fi
1891  
1892      rm -f "${ronin_data_dir}"/blockdata_storage_partition
1893      echo "blockdata_storage_partition=${blockdata_storage_partition}" > "${ronin_data_dir}"/blockdata_storage_partition
1894      chmod +x "${ronin_data_dir}"/blockdata_storage_partition
1895  
1896      rm -f "${ronin_data_dir}"/backup_storage_partition
1897      if [ -n "$backup_storage_partition" ]; then
1898          echo "backup_storage_partition=${backup_storage_partition}" > "${ronin_data_dir}"/backup_storage_partition
1899          chmod +x "${ronin_data_dir}"/backup_storage_partition
1900      fi
1901  }
1902  
1903  #
1904  # Creating Dojo Config files \
1905  # Usage: Copy the template files to conf files. \
1906  # WARNING: These will have default values until _generate_dojo_credentials is ran.
1907  #
1908  _create_dojo_confs() {
1909      for file in ${dojo_path_my_dojo}/conf/*.conf.tpl; do
1910          cp "${file}" "${file:0:-4}"
1911      done
1912  }
1913  
1914  #
1915  # Dojo Credentials Generation \
1916  # Usage: Generates random usernames and passwords for dojo conf
1917  #
1918  _generate_dojo_credentials(){
1919      _load_user_conf
1920      # shellcheck source=./Scripts/generated-credentials.sh
1921      . "${HOME}"/RoninDojo/Scripts/generated-credentials.sh
1922  
1923      sed -i -e "s/BITCOIND_RPC_USER=.*$/BITCOIND_RPC_USER=${BITCOIND_RPC_USER}/" \
1924      -e "s/BITCOIND_RPC_PASSWORD=.*$/BITCOIND_RPC_PASSWORD=${BITCOIND_RPC_PASSWORD}/" \
1925      "${dojo_path_my_dojo}"/conf/docker-bitcoind.conf
1926  
1927      sed -i -e "s/NODE_API_KEY=.*$/NODE_API_KEY=${NODE_API_KEY}/" \
1928      -e "s/NODE_ADMIN_KEY=.*$/NODE_ADMIN_KEY=${NODE_ADMIN_KEY}/" \
1929      -e "s/NODE_JWT_SECRET=.*$/NODE_JWT_SECRET=${NODE_JWT_SECRET}/" \
1930      "${dojo_path_my_dojo}"/conf/docker-node.conf
1931  
1932      sed -i -e "s/MYSQL_ROOT_PASSWORD=.*$/MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}/" \
1933      -e "s/MYSQL_USER=.*$/MYSQL_USER=${MYSQL_USER}/" \
1934      -e "s/MYSQL_PASSWORD=.*$/MYSQL_PASSWORD=${MYSQL_PASSWORD}/" \
1935      "${dojo_path_my_dojo}"/conf/docker-mysql.conf
1936  
1937      sed -i -e "s/EXPLORER_INSTALL=.*$/EXPLORER_INSTALL=on/" \
1938      "${dojo_path_my_dojo}"/conf/docker-explorer.conf
1939  
1940      sed -i -e 's/MEMPOOL_INSTALL=.*$/MEMPOOL_INSTALL=off/' \
1941      -e "s/MEMPOOL_MYSQL_USER=.*$/MEMPOOL_MYSQL_USER=${MEMPOOL_MYSQL_USER}/" \
1942      -e "s/MEMPOOL_MYSQL_PASS=.*$/MEMPOOL_MYSQL_PASS=${MEMPOOL_MYSQL_PASS}/" \
1943      -e "s/MEMPOOL_MYSQL_ROOT_PASSWORD=.*$/MEMPOOL_MYSQL_ROOT_PASSWORD=${MEMPOOL_MYSQL_ROOT_PASSWORD}/" \
1944      "${dojo_path_my_dojo}"/conf/docker-mempool.conf
1945  }
1946  
1947  #
1948  # Backup Dojo confs \
1949  # Usage: Copys users dojo confs to SSD for easy restore if necessary
1950  #
1951  _backup_dojo_confs() {
1952      if [ ! -d ${dojo_backup_dir} ]; then
1953          sudo mkdir -p ${dojo_backup_dir}
1954      fi
1955      if [ ! -w "${dojo_backup_dir}" ]; then
1956          sudo chown -R "$USER":"$USER" "${dojo_backup_dir}"
1957      fi
1958      _create_dir "${dojo_backup_conf}"
1959      sudo rsync -acp --quiet --delete-before "${dojo_path_my_dojo}"/conf/*.conf "${dojo_backup_conf}"
1960  }
1961  
1962  #
1963  # Dojo Conf function \
1964  # Usage: restores/creates and backs up users dojo confs to SSD
1965  #
1966  _restore_or_create_dojo_confs() {
1967      if [ -d "${dojo_backup_conf}" ] && ! grep "BITCOIND_RPC_USER=dojorpc" "${dojo_backup_conf}"/docker-bitcoind.conf 1>/dev/null; then
1968          _print_message "Credentials backup detected and restored..."
1969          sudo chown -R "$USER":"$USER" "${dojo_backup_dir}"
1970          sudo rsync -acp --quiet --delete-before "${dojo_backup_conf}"/*.conf "${dojo_path_my_dojo}"/conf/
1971  
1972          update_all_config_files
1973  
1974      else
1975          _print_message "No unique backup credentials detected. Setting newly generated credentials..."
1976          _create_dojo_confs
1977          _generate_dojo_credentials
1978          if "${is_active_dojo_conf_backup}"; then
1979              _print_message "Backing up newly created credentials..."
1980              _backup_dojo_confs
1981          fi
1982      fi
1983  }
1984  
1985  #
1986  # Installs Network Check Service File
1987  # Usage: Creates a service file that will execute the network-check.sh and verify the system is still connected to the same network
1988  # Note: do not edit without taking _update_32 into account.
1989  #
1990  _install_network_check_service() {
1991      _load_user_conf
1992  
1993      sudo tee "/etc/systemd/system/ronin.network.service" <<EOF >/dev/null
1994  [Unit]
1995  Description=Network Check
1996  After=multi-user.target
1997  After=network.target
1998  Requires=network.target
1999  
2000  [Service]
2001  User=root
2002  Type=oneshot
2003  RemainAfterExit=yes
2004  ExecStart=/bin/bash ${ronin_scripts_dir}/network-check.sh ${ronin_data_dir} ${USER}
2005  Restart=on-failure
2006  RestartSec=30
2007  
2008  [Install]
2009  WantedBy=multi-user.target
2010  EOF
2011  
2012      sudo systemctl daemon-reload
2013      sudo systemctl enable --now --quiet ronin.network
2014  }
2015  
2016  #
2017  # Removes Network Check Service File
2018  #
2019  _uninstall_network_check_service() {
2020      sudo systemctl disable ronin.network
2021      sudo systemctl stop ronin.network
2022      sudo rm -f "/etc/systemd/system/ronin.network.service"
2023      sudo systemctl daemon-reload
2024  }
2025  
2026  
2027  #
2028  # Update a configuration file from template
2029  # Function name and body copied from SamouraiWallet's dojo repo, file /docker/my-dojo/install/upgrade-script.sh
2030  #
2031  update_config_file() {
2032    if [ -f $1 ]; then
2033      sed "s/^#.*//g;s/=.*//g;/^$/d" $1 > ./original.keys.raw
2034      grep -f ./original.keys.raw $1 > ./original.lines.raw
2035  
2036      cp -p $1 "$1.save"
2037      cp -p $2 $1
2038  
2039      while IFS='=' read -r key val ; do
2040        if [[ $OSTYPE == darwin* ]]; then
2041          sed -i "" "s~$key=.*~$key=$val~g" "$1"
2042        else
2043          sed -i "s~$key=.*~$key=$val~g" "$1"
2044        fi
2045      done < ./original.lines.raw
2046  
2047      rm ./original.keys.raw
2048      rm ./original.lines.raw
2049    else
2050      cp $2 $1
2051    fi
2052  }
2053  
2054  update_all_config_files() {
2055      update_config_file "${dojo_path_my_dojo}/conf/docker-common.conf" "${dojo_path_my_dojo}/conf/docker-common.conf.tpl"
2056      update_config_file "${dojo_path_my_dojo}/conf/docker-bitcoind.conf" "${dojo_path_my_dojo}/conf/docker-bitcoind.conf.tpl"
2057      update_config_file "${dojo_path_my_dojo}/conf/docker-mysql.conf" "${dojo_path_my_dojo}/conf/docker-mysql.conf.tpl"
2058      update_config_file "${dojo_path_my_dojo}/conf/docker-node.conf" "${dojo_path_my_dojo}/conf/docker-node.conf.tpl"
2059      update_config_file "${dojo_path_my_dojo}/conf/docker-explorer.conf" "${dojo_path_my_dojo}/conf/docker-explorer.conf.tpl"
2060      update_config_file "${dojo_path_my_dojo}/conf/docker-tor.conf" "${dojo_path_my_dojo}/conf/docker-tor.conf.tpl"
2061      update_config_file "${dojo_path_my_dojo}/conf/docker-indexer.conf" "${dojo_path_my_dojo}/conf/docker-indexer.conf.tpl"
2062      update_config_file "${dojo_path_my_dojo}/conf/docker-mempool.conf" "${dojo_path_my_dojo}/conf/docker-mempool.conf.tpl"
2063  }