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 }