diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..edb8a8fd0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# +https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/main.tmp b/.github/workflows/main.tmp new file mode 100644 index 000000000..afe3205a6 --- /dev/null +++ b/.github/workflows/main.tmp @@ -0,0 +1,15 @@ +name: purge jsdelivr cache + +on: + release: + types: [created] + push: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: purge jsdelivr cache + run: | + curl https://purge.jsdelivr.net/gh/jacyl4/de_GWD@main/client diff --git a/.github/workflows/sha256sum.yml b/.github/workflows/sha256sum.yml new file mode 100644 index 000000000..bd9c3ccc4 --- /dev/null +++ b/.github/workflows/sha256sum.yml @@ -0,0 +1,28 @@ +name: checkSUM + +on: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: sha256sum + run: | + chmod +x sha256sum + ./sha256sum + + - name: Commit + run: | + git config --global user.email jacyl4@gmail.com + git config --global user.name jacyl4 + git add ./resource + git commit -am "Auto sha256sum" + + - name: Push + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9bea4330f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/@init b/@init new file mode 100644 index 000000000..1913b86eb --- /dev/null +++ b/@init @@ -0,0 +1,425 @@ +#!/bin/bash +cat << EOF >/etc/apt/apt.conf.d/01InstallLess +APT::Get::Assume-Yes "true"; +APT::Install-Recommends "false"; +APT::Install-Suggests "false"; +EOF + +cat << EOF >/etc/apt/apt.conf.d/71debconf +Dpkg::Options { + "--force-confdef"; + "--force-confold"; +}; +EOF + +sed -i '/ulimit -SHn/d' /etc/profile +sed -i '/ulimit -c/d' /etc/profile +sed -i '/ulimit -d/d' /etc/profile +sed -i '/ulimit -f/d' /etc/profile +sed -i '/ulimit -m/d' /etc/profile +sed -i '/ulimit -s/d' /etc/profile +sed -i '/ulimit -t/d' /etc/profile +sed -i '/ulimit -u/d' /etc/profile +sed -i '/ulimit -v/d' /etc/profile +sed -i '/HISTCONTROL=/d' /etc/profile +sed -i '/alias reboot=/d' /etc/profile +cat << EOF >>/etc/profile +ulimit -SHn 1000000 +ulimit -c unlimited +ulimit -d unlimited +ulimit -f unlimited +ulimit -m unlimited +ulimit -s unlimited +ulimit -t unlimited +ulimit -u 1000000 +ulimit -v unlimited + +HISTCONTROL=ignoredups +alias reboot="sudo systemctl reboot" +EOF +sed -i '/pam_limits.so/d' /etc/pam.d/common-session +echo "session required pam_limits.so" >>/etc/pam.d/common-session +source /etc/profile + +cat << EOF >/etc/security/limits.conf +root soft nofile 1000000 +root hard nofile 1000000 +root soft nproc 1000000 +root hard nproc 1000000 +root soft core 1000000 +root hard core 1000000 +root hard memlock unlimited +root soft memlock unlimited + +www-data soft nofile 1000000 +www-data hard nofile 1000000 +www-data soft nproc 1000000 +www-data hard nproc 1000000 +www-data soft core 1000000 +www-data hard core 1000000 +www-data hard memlock unlimited +www-data soft memlock unlimited + +* soft nofile 1000000 +* hard nofile 1000000 +* soft nproc 1000000 +* hard nproc 1000000 +* soft core 1000000 +* hard core 1000000 +* hard memlock unlimited +* soft memlock unlimited +EOF + +sed -i '/DefaultLimitCORE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNOFILE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNPROC/d' /etc/systemd/system.conf +cat << EOF >>/etc/systemd/system.conf +DefaultLimitCORE=1000000 +DefaultLimitNOFILE=1000000 +DefaultLimitNPROC=1000000 +EOF +systemctl daemon-reload + +sed -i '/nf_conntrack/d' /etc/modules-load.d/modules.conf +sed -i '/ifb/d' /etc/modules-load.d/modules.conf +cat << EOF >>/etc/modules-load.d/modules.conf +nf_conntrack +ifb +sch_cake +EOF +modprobe nf_conntrack +modprobe ifb +modprobe sch_cake + +cat << EOF >/etc/sysctl.conf +vm.overcommit_memory = 1 +vm.swappiness = 10 +vm.dirty_ratio = 10 +vm.dirty_background_ratio = 5 +fs.nr_open = 1000000 +fs.file-max = 1000000 +fs.inotify.max_user_instances = 819200 +fs.inotify.max_queued_events = 32000 +fs.inotify.max_user_watches = 64000 +net.unix.max_dgram_qlen = 10240 +net.nf_conntrack_max = 131072 +net.netfilter.nf_conntrack_acct = 0 +net.netfilter.nf_conntrack_checksum = 0 +net.netfilter.nf_conntrack_events = 1 +net.netfilter.nf_conntrack_timestamp = 0 +net.netfilter.nf_conntrack_max = 16384 +net.netfilter.nf_conntrack_buckets = 65535 +net.netfilter.nf_conntrack_tcp_loose = 1 +net.netfilter.nf_conntrack_tcp_be_liberal = 1 +net.netfilter.nf_conntrack_tcp_max_retrans = 3 +net.netfilter.nf_conntrack_generic_timeout = 60 +net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 30 +net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15 +net.netfilter.nf_conntrack_tcp_timeout_close = 5 +net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 30 +net.netfilter.nf_conntrack_tcp_timeout_established = 3600 +net.netfilter.nf_conntrack_sctp_timeout_established = 3600 +net.netfilter.nf_conntrack_udp_timeout = 15 +net.netfilter.nf_conntrack_udp_timeout_stream = 45 +net.core.somaxconn = 65535 +net.core.netdev_max_backlog = 262144 +net.core.optmem_max = 8388608 +net.core.rmem_default = 8388608 +net.core.wmem_default = 8388608 +net.core.rmem_max = 33554432 +net.core.wmem_max = 33554432 +net.mptcp.enabled = 1 +net.ipv4.conf.all.arp_accept = 0 +net.ipv4.conf.default.arp_accept = 0 +net.ipv4.conf.all.arp_announce = 2 +net.ipv4.conf.default.arp_announce = 2 +net.ipv4.conf.all.arp_ignore = 1 +net.ipv4.conf.default.arp_ignore = 1 +net.ipv4.conf.all.rp_filter = 0 +net.ipv4.conf.default.rp_filter = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.secure_redirects = 0 +net.ipv4.conf.default.secure_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv4.conf.all.route_localnet = 1 +net.ipv4.route.flush = 1 +net.ipv4.ip_local_port_range = 1024 65535 +net.ipv4.ip_forward = 1 +net.ipv4.conf.all.forwarding = 1 +net.ipv4.conf.default.forwarding = 1 +net.ipv4.ip_no_pmtu_disc = 0 +net.ipv4.udp_rmem_min = 262144 +net.ipv4.udp_wmem_min = 262144 +net.ipv4.tcp_mem = 8388608 8388608 8388608 +net.ipv4.tcp_rmem = 8192 262144 16777216 +net.ipv4.tcp_wmem = 8192 262144 16777216 +net.ipv4.tcp_max_tw_buckets = 131072 +net.ipv4.tcp_max_orphans = 131072 +net.ipv4.tcp_max_syn_backlog = 32768 +net.ipv4.tcp_limit_output_bytes = 1048576 +net.ipv4.tcp_adv_win_scale = 1 +net.ipv4.tcp_moderate_rcvbuf = 1 +net.ipv4.tcp_window_scaling = 1 +net.ipv4.tcp_workaround_signed_windows = 0 +net.ipv4.tcp_mtu_probing = 0 +net.ipv4.tcp_mtu_probe_floor = 48 +net.ipv4.tcp_base_mss = 1024 +net.ipv4.tcp_no_metrics_save = 0 +net.ipv4.tcp_no_ssthresh_metrics_save = 1 +net.ipv4.tcp_available_ulp = espintcp mptcp +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_dsack = 1 +net.ipv4.tcp_frto = 0 +net.ipv4.tcp_recovery = 1 +net.ipv4.tcp_early_retrans = 3 +net.ipv4.tcp_min_rtt_wlen = 120 +net.ipv4.tcp_reordering = 3 +net.ipv4.tcp_ecn = 0 +net.ipv4.tcp_fin_timeout = 10 +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_fastopen_blackhole_timeout_sec = 0 +net.ipv4.tcp_fastopen_key = 00000000-00000000-00000000-00000000 +net.ipv4.tcp_keepalive_time = 7200 +net.ipv4.tcp_keepalive_intvl = 75 +net.ipv4.tcp_keepalive_probes = 9 +net.ipv4.tcp_timestamps = 0 +net.ipv4.tcp_syncookies = 0 +net.ipv4.tcp_tw_reuse = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_retries1 = 3 +net.ipv4.tcp_retries2 = 8 +net.ipv4.tcp_orphan_retries = 0 +net.ipv4.tcp_challenge_ack_limit = 100000 +net.ipv4.tcp_slow_start_after_idle = 0 +net.ipv4.tcp_autocorking = 0 +net.ipv4.tcp_rfc1337 = 1 +net.core.default_qdisc = cake +EOF + +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf +if [[ $(uname -r) =~ "bbrplus" ]]; then + echo "net.ipv4.tcp_congestion_control = bbrplus" >>/etc/sysctl.conf +else + echo "net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.conf +fi +sysctl -p >/dev/null 2>&1 + +dpkg --configure -a +cat << EOF >/etc/apt/sources.list +deb http://deb.debian.org/debian bookworm main non-free-firmware +deb-src http://deb.debian.org/debian bookworm main non-free-firmware + +deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware +deb-src http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware + +deb http://deb.debian.org/debian bookworm-updates main non-free-firmware +deb-src http://deb.debian.org/debian bookworm-updates main non-free-firmware + +deb http://deb.debian.org/debian bookworm-backports main non-free-firmware +deb-src http://deb.debian.org/debian bookworm-backports main non-free-firmware +EOF +apt update --fix-missing && apt upgrade --allow-downgrades -y +apt full-upgrade -y && apt --purge autoremove -y && apt clean -y && apt autoclean -y + +[[ -n $(dpkg -l | awk '{print$2}' | grep '^haveged$') ]] && apt remove --purge haveged +[[ -n $(dpkg -l | awk '{print$2}' | grep '^os-prober$') ]] && apt remove --purge os-prober +[[ -n $(dpkg -l | awk '{print$2}' | grep '^systemd-timesyncd$') ]] && apt remove --purge systemd-timesyncd + +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^sudo$') ]] && aptPKG+=(sudo) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^wget$') ]] && aptPKG+=(wget) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^curl$') ]] && aptPKG+=(curl) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^git$') ]] && aptPKG+=(git) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^locales$') ]] && aptPKG+=(locales) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ethtool$') ]] && aptPKG+=(ethtool) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ca-certificates$') ]] && aptPKG+=(ca-certificates) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^apt-transport-https$') ]] && aptPKG+=(apt-transport-https) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^gnupg2$') ]] && aptPKG+=(gnupg2) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^unzip$') ]] && aptPKG+=(unzip) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^jq$') ]] && aptPKG+=(jq) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^rng-tools-debian$') ]] && aptPKG+=(rng-tools-debian) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^chrony$') ]] && aptPKG+=(chrony) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^irqbalance$') ]] && [[ $(nproc --all) -gt 1 ]] && aptPKG+=(irqbalance) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) + +cat << EOF >/etc/default/rng-tools-debian +# -*- mode: sh -*- +#- +# Configuration for the rng-tools-debian initscript + +# Set to the input source for random data, leave undefined +# for the initscript to attempt auto-detection. Set to /dev/null +# for the viapadlock driver. +#HRNGDEVICE=/dev/hwrng +#HRNGDEVICE=/dev/null +HRNGDEVICE=/dev/urandom + +# Additional options to send to rngd. See the rngd(8) manpage for +# more information. Do not specify -r/--rng-device here, use +# HRNGDEVICE for that instead. +#RNGDOPTIONS="--hrng=intelfwh --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viakernel --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viapadlock --fill-watermark=90% --feed-interval=1" +# For TPM (also add tpm-rng to /etc/initramfs-tools/modules or /etc/modules): +#RNGDOPTIONS="--fill-watermark=90% --feed-interval=1" + +# If you need to configure which RNG to use, do it here: +#HRNGSELECT="virtio_rng.0" +# Use this instead of sysfsutils, which starts too late. +EOF +systemctl restart rng-tools + +cat << EOF >/etc/chrony/chrony.conf +server time.cloud.tencent.com iburst +server time4.cloud.tencent.com iburst +server time5.cloud.tencent.com iburst +server ntp.aliyun.com iburst +server ntp6.aliyun.com iburst +server ntp7.aliyun.com iburst + +driftfile /var/lib/chrony/chrony.drift +logdir /var/log/chrony +maxupdateskew 100.0 +rtcsync +makestep 1 3 +leapsectz right/UTC +EOF +systemctl restart chrony +systemctl enable chrony >/dev/null 2>&1 + +localeSet=`cat << EOF +LANG=en_US.UTF-8 +LANGUAGE=en_US.UTF-8 +LC_CTYPE="en_US.UTF-8" +LC_NUMERIC="en_US.UTF-8" +LC_TIME="en_US.UTF-8" +LC_COLLATE="en_US.UTF-8" +LC_MONETARY="en_US.UTF-8" +LC_MESSAGES="en_US.UTF-8" +LC_PAPER="en_US.UTF-8" +LC_NAME="en_US.UTF-8" +LC_ADDRESS="en_US.UTF-8" +LC_TELEPHONE="en_US.UTF-8" +LC_MEASUREMENT="en_US.UTF-8" +LC_IDENTIFICATION="en_US.UTF-8" +LC_ALL=en_US.UTF-8 +EOF +` +if [[ -z $(locale -a | grep "en_US.utf8") ]]; then +echo "$localeSet" >/etc/default/locale +echo "en_US.UTF-8 UTF-8" >/etc/locale.gen +locale-gen "en_US.UTF-8" +update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 +fi + +[[ $(date +"%Z %z") != "CST +0800" ]] && timedatectl set-timezone "Asia/Shanghai" +timedatectl set-local-rtc 0 >/dev/null 2>&1 +timedatectl set-ntp true + +[[ -f "/etc/rc.local" ]] && [[ -n $(grep 'tc qdisc' /etc/rc.local) ]] && rm -rf /etc/rc.local + +cat << EOF >/etc/rc_online.local +#!/bin/bash +echo madvise >/sys/kernel/mm/transparent_hugepage/enabled + +$(which ip) route show table local | grep ' dev lo ' | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 9088 initcwnd 1000 initrwnd 1000 fastopen_no_cookie 1 congctl lock cubic +done + +NIC_local=\$($(which ip) route | grep -v 'scope link' | awk -F' dev ' '{print\$2}' | cut -d' ' -f1) +$(which ip) route show table local | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + +$(which ip) route | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 advmss 1440 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + + + +NIC_device=\$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device') +for ifb in \$(echo \$NIC_device | xargs -n 1 | grep 'virtual' | awk -F'/' '{print\$NF}' | grep '^ifb'); do +$(which ip) link set \$ifb down +$(which ip) link delete \$ifb +done + +$(which ip) link set lo qlen 4096 mtu 9088 +$(which tc) qdisc del dev lo root >/dev/null 2>&1 +$(which tc) qdisc add dev lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw egress + +$(which ip) link add name ifb4lo type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev lo ingress >/dev/null 2>&1 +$(which tc) qdisc add dev lo handle ffff: ingress +$(which tc) qdisc del dev ifb4lo root >/dev/null 2>&1 +$(which tc) qdisc add dev ifb4lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw ingress +$(which ip) link set ifb4lo qlen 4096 mtu 9088 +$(which ip) link set ifb4lo up +$(which tc) filter add dev lo parent ffff: matchall action mirred egress redirect dev ifb4lo + +echo \$NIC_device | xargs -n 1 | grep 'virtual' | grep -v 'ifb' | awk -F'/' '{print\$NF}' | grep -v '^lo\$' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited metro diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth +done + +echo \$NIC_device | xargs -n 1 | grep -v 'virtual' | awk -F'/' '{print\$NF}' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter-aggressive ethernet egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited regional diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter-aggressive ethernet ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth + +$(which ethtool) -s \$line duplex full >/dev/null 2>&1 +$(which ethtool) -K \$line rx on tx on sg off tso off gso off gro off lro off >/dev/null 2>&1 +done + +$(which ip) tcp_metrics flush +$(which ip) route flush cache +EOF +chmod +x /etc/rc_online.local +/etc/rc_online.local + + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/\/etc\/rc_online.local/d' /tmp/now.cron +cat << EOF >>/tmp/now.cron +@reboot sleep 30 && /etc/rc_online.local +EOF +crontab /tmp/now.cron +rm -rf /tmp/now.cron + +date -s "$(wget -qSO- --max-redirect=0 aliyun.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" | grep -v ' 08:00:00 ' +[[ $? -ne "0" ]] && date -s "$(wget -qSO- --max-redirect=0 baidu.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" +hwclock -w diff --git a/@initB b/@initB new file mode 100644 index 000000000..2fa78f148 --- /dev/null +++ b/@initB @@ -0,0 +1,392 @@ +#!/bin/bash +cat << EOF >/etc/apt/apt.conf.d/01InstallLess +APT::Get::Assume-Yes "true"; +APT::Install-Recommends "false"; +APT::Install-Suggests "false"; +EOF + +cat << EOF >/etc/apt/apt.conf.d/71debconf +Dpkg::Options { + "--force-confdef"; + "--force-confold"; +}; +EOF + +sed -i '/ulimit -SHn/d' /etc/profile +sed -i '/ulimit -c/d' /etc/profile +sed -i '/ulimit -d/d' /etc/profile +sed -i '/ulimit -f/d' /etc/profile +sed -i '/ulimit -m/d' /etc/profile +sed -i '/ulimit -s/d' /etc/profile +sed -i '/ulimit -t/d' /etc/profile +sed -i '/ulimit -u/d' /etc/profile +sed -i '/ulimit -v/d' /etc/profile +sed -i '/HISTCONTROL=/d' /etc/profile +sed -i '/alias reboot=/d' /etc/profile +cat << EOF >>/etc/profile +ulimit -SHn 1000000 +ulimit -c unlimited +ulimit -d unlimited +ulimit -f unlimited +ulimit -m unlimited +ulimit -s unlimited +ulimit -t unlimited +ulimit -u 1000000 +ulimit -v unlimited + +HISTCONTROL=ignoredups +alias reboot="sudo systemctl reboot" +EOF +sed -i '/pam_limits.so/d' /etc/pam.d/common-session +echo "session required pam_limits.so" >>/etc/pam.d/common-session +source /etc/profile + +cat << EOF >/etc/security/limits.conf +root soft nofile 1000000 +root hard nofile 1000000 +root soft nproc 1000000 +root hard nproc 1000000 +root soft core 1000000 +root hard core 1000000 +root hard memlock unlimited +root soft memlock unlimited + +www-data soft nofile 1000000 +www-data hard nofile 1000000 +www-data soft nproc 1000000 +www-data hard nproc 1000000 +www-data soft core 1000000 +www-data hard core 1000000 +www-data hard memlock unlimited +www-data soft memlock unlimited + +* soft nofile 1000000 +* hard nofile 1000000 +* soft nproc 1000000 +* hard nproc 1000000 +* soft core 1000000 +* hard core 1000000 +* hard memlock unlimited +* soft memlock unlimited +EOF + +sed -i '/DefaultLimitCORE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNOFILE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNPROC/d' /etc/systemd/system.conf +cat << EOF >>/etc/systemd/system.conf +DefaultLimitCORE=1000000 +DefaultLimitNOFILE=1000000 +DefaultLimitNPROC=1000000 +EOF +systemctl daemon-reload + +sed -i '/nf_conntrack/d' /etc/modules-load.d/modules.conf +sed -i '/ifb/d' /etc/modules-load.d/modules.conf +cat << EOF >>/etc/modules-load.d/modules.conf +nf_conntrack +ifb +sch_cake +EOF +modprobe nf_conntrack +modprobe ifb +modprobe sch_cake + +cat << EOF >/etc/sysctl.conf +vm.overcommit_memory = 1 +vm.swappiness = 10 +vm.dirty_ratio = 10 +vm.dirty_background_ratio = 5 +fs.nr_open = 1000000 +fs.file-max = 1000000 +fs.inotify.max_user_instances = 819200 +fs.inotify.max_queued_events = 32000 +fs.inotify.max_user_watches = 64000 +net.unix.max_dgram_qlen = 10240 +net.nf_conntrack_max = 131072 +net.netfilter.nf_conntrack_acct = 0 +net.netfilter.nf_conntrack_checksum = 0 +net.netfilter.nf_conntrack_events = 1 +net.netfilter.nf_conntrack_timestamp = 0 +net.netfilter.nf_conntrack_max = 16384 +net.netfilter.nf_conntrack_buckets = 65535 +net.netfilter.nf_conntrack_tcp_loose = 1 +net.netfilter.nf_conntrack_tcp_be_liberal = 1 +net.netfilter.nf_conntrack_tcp_max_retrans = 3 +net.netfilter.nf_conntrack_generic_timeout = 60 +net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 30 +net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15 +net.netfilter.nf_conntrack_tcp_timeout_close = 5 +net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 30 +net.netfilter.nf_conntrack_tcp_timeout_established = 3600 +net.netfilter.nf_conntrack_sctp_timeout_established = 3600 +net.netfilter.nf_conntrack_udp_timeout = 15 +net.netfilter.nf_conntrack_udp_timeout_stream = 45 +net.core.somaxconn = 65535 +net.core.netdev_max_backlog = 262144 +net.core.optmem_max = 8388608 +net.core.rmem_default = 8388608 +net.core.wmem_default = 8388608 +net.core.rmem_max = 33554432 +net.core.wmem_max = 33554432 +net.mptcp.enabled = 1 +net.ipv4.conf.all.arp_accept = 0 +net.ipv4.conf.default.arp_accept = 0 +net.ipv4.conf.all.arp_announce = 2 +net.ipv4.conf.default.arp_announce = 2 +net.ipv4.conf.all.arp_ignore = 1 +net.ipv4.conf.default.arp_ignore = 1 +net.ipv4.conf.all.rp_filter = 0 +net.ipv4.conf.default.rp_filter = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.secure_redirects = 0 +net.ipv4.conf.default.secure_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv4.conf.all.route_localnet = 1 +net.ipv4.route.flush = 1 +net.ipv4.ip_local_port_range = 1024 65535 +net.ipv4.ip_forward = 1 +net.ipv4.conf.all.forwarding = 1 +net.ipv4.conf.default.forwarding = 1 +net.ipv4.ip_no_pmtu_disc = 0 +net.ipv4.udp_rmem_min = 262144 +net.ipv4.udp_wmem_min = 262144 +net.ipv4.tcp_mem = 8388608 8388608 8388608 +net.ipv4.tcp_rmem = 8192 262144 16777216 +net.ipv4.tcp_wmem = 8192 262144 16777216 +net.ipv4.tcp_max_tw_buckets = 131072 +net.ipv4.tcp_max_orphans = 131072 +net.ipv4.tcp_max_syn_backlog = 32768 +net.ipv4.tcp_limit_output_bytes = 1048576 +net.ipv4.tcp_adv_win_scale = 1 +net.ipv4.tcp_moderate_rcvbuf = 1 +net.ipv4.tcp_window_scaling = 1 +net.ipv4.tcp_workaround_signed_windows = 0 +net.ipv4.tcp_mtu_probing = 0 +net.ipv4.tcp_mtu_probe_floor = 48 +net.ipv4.tcp_base_mss = 1024 +net.ipv4.tcp_no_metrics_save = 0 +net.ipv4.tcp_no_ssthresh_metrics_save = 1 +net.ipv4.tcp_available_ulp = espintcp mptcp +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_dsack = 1 +net.ipv4.tcp_frto = 0 +net.ipv4.tcp_recovery = 1 +net.ipv4.tcp_early_retrans = 3 +net.ipv4.tcp_min_rtt_wlen = 120 +net.ipv4.tcp_reordering = 3 +net.ipv4.tcp_ecn = 0 +net.ipv4.tcp_fin_timeout = 10 +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_fastopen_blackhole_timeout_sec = 0 +net.ipv4.tcp_fastopen_key = 00000000-00000000-00000000-00000000 +net.ipv4.tcp_keepalive_time = 7200 +net.ipv4.tcp_keepalive_intvl = 75 +net.ipv4.tcp_keepalive_probes = 9 +net.ipv4.tcp_timestamps = 0 +net.ipv4.tcp_syncookies = 0 +net.ipv4.tcp_tw_reuse = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_retries1 = 3 +net.ipv4.tcp_retries2 = 8 +net.ipv4.tcp_orphan_retries = 0 +net.ipv4.tcp_challenge_ack_limit = 100000 +net.ipv4.tcp_slow_start_after_idle = 0 +net.ipv4.tcp_autocorking = 0 +net.ipv4.tcp_rfc1337 = 1 +net.core.default_qdisc = cake +EOF + +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf +if [[ $(uname -r) =~ "bbrplus" ]]; then + echo "net.ipv4.tcp_congestion_control = bbrplus" >>/etc/sysctl.conf +else + echo "net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.conf +fi +sysctl -p >/dev/null 2>&1 + +dpkg --configure -a +cat << EOF >/etc/apt/sources.list +deb http://cloudfront.debian.net/debian buster main contrib non-free +deb http://cloudfront.debian.net/debian buster-updates main contrib non-free +deb http://cloudfront.debian.net/debian buster-backports main contrib non-free +deb http://cloudfront.debian.net/debian-security buster/updates main contrib non-free +EOF +apt update --fix-missing && apt upgrade --allow-downgrades -y +apt full-upgrade -y && apt --purge autoremove -y && apt clean -y && apt autoclean -y + +[[ -n $(dpkg -l | awk '{print$2}' | grep '^os-prober$') ]] && apt remove --purge os-prober +[[ -n $(dpkg -l | awk '{print$2}' | grep '^systemd-timesyncd$') ]] && apt remove --purge systemd-timesyncd + +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^sudo$') ]] && aptPKG+=(sudo) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^wget$') ]] && aptPKG+=(wget) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^curl$') ]] && aptPKG+=(curl) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^git$') ]] && aptPKG+=(git) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^locales$') ]] && aptPKG+=(locales) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ethtool$') ]] && aptPKG+=(ethtool) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ca-certificates$') ]] && aptPKG+=(ca-certificates) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^apt-transport-https$') ]] && aptPKG+=(apt-transport-https) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^gnupg2$') ]] && aptPKG+=(gnupg2) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^unzip$') ]] && aptPKG+=(unzip) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^jq$') ]] && aptPKG+=(jq) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^haveged$') ]] && aptPKG+=(haveged) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^chrony$') ]] && aptPKG+=(chrony) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^irqbalance$') ]] && [[ $(nproc --all) -gt 1 ]] && aptPKG+=(irqbalance) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) + +systemctl restart haveged + +cat << EOF >/etc/chrony/chrony.conf +server time.cloud.tencent.com iburst +server time4.cloud.tencent.com iburst +server time5.cloud.tencent.com iburst +server ntp.aliyun.com iburst +server ntp6.aliyun.com iburst +server ntp7.aliyun.com iburst + +driftfile /var/lib/chrony/chrony.drift +logdir /var/log/chrony +maxupdateskew 100.0 +rtcsync +makestep 1 3 +leapsectz right/UTC +EOF +systemctl restart chrony +systemctl enable chrony >/dev/null 2>&1 + +localeSet=`cat << EOF +LANG=en_US.UTF-8 +LANGUAGE=en_US.UTF-8 +LC_CTYPE="en_US.UTF-8" +LC_NUMERIC="en_US.UTF-8" +LC_TIME="en_US.UTF-8" +LC_COLLATE="en_US.UTF-8" +LC_MONETARY="en_US.UTF-8" +LC_MESSAGES="en_US.UTF-8" +LC_PAPER="en_US.UTF-8" +LC_NAME="en_US.UTF-8" +LC_ADDRESS="en_US.UTF-8" +LC_TELEPHONE="en_US.UTF-8" +LC_MEASUREMENT="en_US.UTF-8" +LC_IDENTIFICATION="en_US.UTF-8" +LC_ALL=en_US.UTF-8 +EOF +` +if [[ -z $(locale -a | grep "en_US.utf8") ]]; then +echo "$localeSet" >/etc/default/locale +echo "en_US.UTF-8 UTF-8" >/etc/locale.gen +locale-gen "en_US.UTF-8" +update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 +fi + +[[ $(date +"%Z %z") != "CST +0800" ]] && timedatectl set-timezone "Asia/Shanghai" +timedatectl set-local-rtc 0 >/dev/null 2>&1 +timedatectl set-ntp true + +[[ -f "/etc/rc.local" ]] && [[ -n $(grep 'tc qdisc' /etc/rc.local) ]] && rm -rf /etc/rc.local + +cat << EOF >/etc/rc_online.local +#!/bin/bash +echo madvise >/sys/kernel/mm/transparent_hugepage/enabled + +$(which ip) route show table local | grep ' dev lo ' | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 9088 initcwnd 1000 initrwnd 1000 fastopen_no_cookie 1 congctl lock cubic +done + +NIC_local=\$($(which ip) route | grep -v 'scope link' | awk -F' dev ' '{print\$2}' | cut -d' ' -f1) +$(which ip) route show table local | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + +$(which ip) route | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 advmss 1440 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + + + +NIC_device=\$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device') +for ifb in \$(echo \$NIC_device | xargs -n 1 | grep 'virtual' | awk -F'/' '{print\$NF}' | grep '^ifb'); do +$(which ip) link set \$ifb down +$(which ip) link delete \$ifb +done + +$(which ip) link set lo qlen 4096 mtu 9088 +$(which tc) qdisc del dev lo root >/dev/null 2>&1 +$(which tc) qdisc add dev lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw egress + +$(which ip) link add name ifb4lo type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev lo ingress >/dev/null 2>&1 +$(which tc) qdisc add dev lo handle ffff: ingress +$(which tc) qdisc del dev ifb4lo root >/dev/null 2>&1 +$(which tc) qdisc add dev ifb4lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw ingress +$(which ip) link set ifb4lo qlen 4096 mtu 9088 +$(which ip) link set ifb4lo up +$(which tc) filter add dev lo parent ffff: matchall action mirred egress redirect dev ifb4lo + +echo \$NIC_device | xargs -n 1 | grep 'virtual' | grep -v 'ifb' | awk -F'/' '{print\$NF}' | grep -v '^lo\$' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited metro diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth +done + +echo \$NIC_device | xargs -n 1 | grep -v 'virtual' | awk -F'/' '{print\$NF}' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter-aggressive ethernet egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited regional diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter-aggressive ethernet ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth + +$(which ethtool) -s \$line duplex full >/dev/null 2>&1 +$(which ethtool) -K \$line rx on tx on sg off tso off gso off gro off lro off >/dev/null 2>&1 +done + +$(which ip) tcp_metrics flush +$(which ip) route flush cache +EOF +chmod +x /etc/rc_online.local +/etc/rc_online.local + + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/\/etc\/rc_online.local/d' /tmp/now.cron +cat << EOF >>/tmp/now.cron +@reboot sleep 30 && /etc/rc_online.local +EOF +crontab /tmp/now.cron +rm -rf /tmp/now.cron + +date -s "$(wget -qSO- --max-redirect=0 aliyun.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" | grep -v ' 08:00:00 ' +[[ $? -ne "0" ]] && date -s "$(wget -qSO- --max-redirect=0 baidu.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" +hwclock -w diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 000000000..e23ece2c8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..7a095ea52 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# 寒月 +* 具备流量整形加速的旁路网关 +* 仅供学习与研究,不支持机场的双端自建方案 + +[![Telegram](https://cdn.jsdelivr.net/gh/Patrolavia/telegram-badge@8fe3382b3fd3a1c533ba270e608035a27e430c2e/chat.svg)](https://t.me/de_GWD_DQ) + + +## Server (amd64 & arm64) support kvm xen openvz lxc and so on: +``` +apt install -y wget +bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/jacyl4/de_GWD/main/server) +``` + +![de_GWD 0](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/0.png) + +## Client (amd64 & arm64): +``` +apt install -y wget +bash <(wget --no-check-certificate -qO- https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/de_GWD/main/client) +``` +或 + +手动上传client文件与de_GWD压缩包后 +``` +chmod +x client +./client +``` + +![de_GWD 1](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/1.png) +![de_GWD 2](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/2.png) +![de_GWD 3](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/3.png) +![de_GWD 4](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/4.png) +![de_GWD 5](https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/screenshot/5.png) + +## Manual: +没有文档 + +## Thanks to +* [ XTLS/Xray-core ](https://github.com/XTLS/Xray-core) +* [ coredns/coredns ](https://github.com/coredns/coredns) +* [ pymumu/smartdns ](https://github.com/pymumu/smartdns) +* [ IrineSistiana/mosdns ](https://github.com/IrineSistiana/mosdns) +* [ m13253/dns-over-https ](https://github.com/m13253/dns-over-https) +* [ pi-hole/pi-hole ](https://github.com/pi-hole/pi-hole) +* [ mmotti/pihole-regex ](https://github.com/mmotti/pihole-regex) +* [ Loyalsoldier/v2ray-rules-dat ](https://github.com/Loyalsoldier/v2ray-rules-dat) +* [ makotom/cfspeed ](https://github.com/makotom/cfspeed) +* [ UJX6N/bbrplus-6.x ](https://github.com/UJX6N/bbrplus-6.x_Mainline) +* [ mzz2017/lkl-haproxy ](https://github.com/mzz2017/lkl-haproxy) +* [ xanmod/linux ](https://github.com/xanmod/linux) +* [ tsl0922/ttyd ](https://github.com/tsl0922/ttyd) +* [ mikefarah/yq ](https://github.com/mikefarah/yq) +* [ nyanmisaka/jellyfin ](https://hub.docker.com/r/nyanmisaka/jellyfin) +* [ dani-garcia/vaultwarden ](https://github.com/dani-garcia/vaultwarden) + +## Stargazers over time +[![Stargazers over time](https://starchart.cc/jacyl4/de_GWD.svg)](https://starchart.cc/jacyl4/de_GWD) diff --git a/client b/client new file mode 100644 index 000000000..535b58ebd --- /dev/null +++ b/client @@ -0,0 +1,2781 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + +chmod 777 /tmp +architecture=$(dpkg --print-architecture) +export DEBIAN_FRONTEND=noninteractive +TTYD_Ver="1.7.3" +branch="main" + + +installCMD=`cat << EOF +bash <(wget --no-check-certificate -qO- https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/de_GWD/main/client) +EOF +` + + +if [[ $architecture = "arm64" ]];then +chnAPTsource="mirrors.tuna.tsinghua.edu.cn" +elif [[ $architecture = "amd64" ]]; then +chnAPTsource="mirrors.aliyun.com" +fi + +pkgDEP1(){ +if [[ $architecture = "arm64" ]];then +unset Freeze_Package +Freeze_Package+=($(dpkg -l | grep 'linux-u-boot-' | awk '{print $2}')) +Freeze_Package+=($(dpkg -l | grep 'linux-image-' | awk '{print $2}')) +Freeze_Package+=($(dpkg -l | grep 'linux-headers-' | awk '{print $2}')) +Freeze_Package+=($(dpkg -l | grep 'linux-dtb-' | awk '{print $2}')) +echo ${Freeze_Package[@]} | xargs -n1 apt-mark hold +fi + +[[ -n $(dpkg -l | awk '{print$2}' | grep '^ipset$') ]] && apt remove --purge ipset +[[ -n $(dpkg -l | awk '{print$2}' | grep '^haveged$') ]] && apt remove --purge haveged +[[ -n $(dpkg -l | awk '{print$2}' | grep '^os-prober$') ]] && apt remove --purge os-prober +[[ -n $(dpkg -l | awk '{print$2}' | grep '^systemd-timesyncd$') ]] && apt remove --purge systemd-timesyncd + +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^sudo$') ]] && aptPKG+=(sudo) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^wget$') ]] && aptPKG+=(wget) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^curl$') ]] && aptPKG+=(curl) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^git$') ]] && aptPKG+=(git) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^locales$') ]] && aptPKG+=(locales) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^netcat-openbsd$') ]] && aptPKG+=(netcat-openbsd) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^lsof$') ]] && aptPKG+=(lsof) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^dnsutils$') ]] && aptPKG+=(dnsutils) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^net-tools$') ]] && aptPKG+=(net-tools) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^resolvconf$') ]] && aptPKG+=(resolvconf) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^nftables$') ]] && aptPKG+=(nftables) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ca-certificates$') ]] && aptPKG+=(ca-certificates) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^apt-transport-https$') ]] && aptPKG+=(apt-transport-https) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^gnupg2$') ]] && aptPKG+=(gnupg2) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^unzip$') ]] && aptPKG+=(unzip) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^jq$') ]] && aptPKG+=(jq) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^bc$') ]] && aptPKG+=(bc) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^moreutils$') ]] && aptPKG+=(moreutils) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^rng-tools-debian$') ]] && aptPKG+=(rng-tools-debian) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^chrony$') ]] && aptPKG+=(chrony) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^irqbalance$') ]] && [[ $(nproc --all) -gt 1 ]] && aptPKG+=(irqbalance) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) +} + +pkgDEP2(){ +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^psmisc$') ]] && aptPKG+=(psmisc) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^dns-root-data$') ]] && aptPKG+=(dns-root-data) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^idn2$') ]] && aptPKG+=(idn2) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ethtool$') ]] && aptPKG+=(ethtool) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^tmux$') ]] && aptPKG+=(tmux) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^socat$') ]] && aptPKG+=(socat) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^zip$') ]] && aptPKG+=(zip) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^lighttpd$') ]] && aptPKG+=(lighttpd) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-fpm$') ]] && aptPKG+=(php7.4-fpm) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-cgi$') ]] && aptPKG+=(php7.4-cgi) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-sqlite3$') ]] && aptPKG+=(php7.4-sqlite3) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-xml$') ]] && aptPKG+=(php7.4-xml) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-intl$') ]] && aptPKG+=(php7.4-intl) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-json$') ]] && aptPKG+=(php7.4-json) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^sqlite3$') ]] && aptPKG+=(sqlite3) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^libjemalloc2') ]] && aptPKG+=(libjemalloc2) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^libtcmalloc') ]] && aptPKG+=(google-perftools) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) +} + +checkSum(){ +sha256sumL=$(sha256sum $1 2>/dev/null | awk '{print$1}') +if [[ $sha256sumL = $2 ]]; then + echo "true" +elif [[ $sha256sumL != $2 ]]; then + echo "false" +fi +} + + + +preDL(){ +mkdir -p /opt/de_GWD +mkdir -p /opt/de_GWD/.repo + +sha256sum_IPchnroute=$(curl -ksSLo- https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/chnroute/main/IPchnroute.sha256sum) +if [[ $(checkSum /opt/de_GWD/.repo/IPchnroute $sha256sum_IPchnroute) = "false" ]]; then +rm -rf /tmp/IPchnroute +wget --no-check-certificate --show-progress -cqO /tmp/IPchnroute https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/chnroute/main/IPchnroute +[[ $(checkSum /tmp/IPchnroute $sha256sum_IPchnroute) = "false" ]] && echo -e "${WHITE}IPchnroute${RED} Download Failed${cRES}" && exit +[[ $(checkSum /tmp/IPchnroute $sha256sum_IPchnroute) = "true" ]] && mv -f /tmp/IPchnroute /opt/de_GWD/.repo/IPchnroute +fi + +if [[ -f "./de_GWD_$architecture.zip" ]]; then + mv -f ./de_GWD_$architecture.zip /opt/de_GWD/.repo/de_GWD.zip +else + sha256sum_de_GWD=$(curl -ksSLo- https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/de_GWD/main/de_GWD_"$architecture".zip.sha256sum) + if [[ $(checkSum /opt/de_GWD/.repo/de_GWD.zip $sha256sum_de_GWD) = "false" ]]; then + rm -rf /tmp/de_GWD.zip + wget --no-check-certificate --show-progress -cqO /tmp/de_GWD.zip https://ghproxy.com/https://raw.githubusercontent.com/jacyl4/de_GWD/main/de_GWD_"$architecture".zip + [[ $(checkSum /tmp/de_GWD.zip $sha256sum_de_GWD) = "false" ]] && rm -rf /tmp/de_GWD.zip && wget --no-check-certificate --show-progress -cqO /tmp/de_GWD.zip https://de-gwd.accxio.workers.dev/de_GWD_"$architecture".zip + [[ $(checkSum /tmp/de_GWD.zip $sha256sum_de_GWD) = "false" ]] && echo -e "${WHITE}de_GWD Zip${RED} Download Failed${cRES}" && exit + [[ $(checkSum /tmp/de_GWD.zip $sha256sum_de_GWD) = "true" ]] && mv -f /tmp/de_GWD.zip /opt/de_GWD/.repo/de_GWD.zip + fi +fi + +[[ -z $(unzip -tq /opt/de_GWD/.repo/de_GWD.zip | grep "No errors detected in compressed data") ]] && echo -e "${WHITE}de_GWD Zip${RED} Download Failed${cRES}" && exit + +cat << "EOF" >/opt/de_GWD/tcpTime +#!/bin/bash +echo +date -s "$(curl -sI aliyun.com| grep -i '^date:'|cut -d' ' -f2-)" +[[ $? -ne "0" ]] && date -s "$(wget -qSO- --max-redirect=0 --dns-timeout=3 baidu.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" +hwclock -w +echo +EOF +chmod +x /opt/de_GWD/tcpTime +/opt/de_GWD/tcpTime +} + + + +repoDL(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Repo Download${cRES}\r\c" +sha256sum_nginx=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/nginx/nginx_"$architecture".sha256sum) +sha256sum_nginxConf=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/nginx/nginxConf.zip.sha256sum) +sha256sum_client=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/client/Archive.zip.sha256sum) + +if [[ $(checkSum /usr/sbin/nginx $sha256sum_nginx) = "false" ]]; then +rm -rf /tmp/nginx +wget --show-progress -cqO /tmp/nginx https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/nginx/nginx_"$architecture" +[[ $(checkSum /tmp/nginx $sha256sum_nginx) = "false" ]] && echo -e "${WHITE}NGINX Core${RED} Download Failed${cRES}" && exit +[[ $(checkSum /tmp/nginx $sha256sum_nginx) = "true" ]] && mv -f /tmp/nginx /usr/sbin/nginx && chmod +x /usr/sbin/nginx +fi + +if [[ $(checkSum /opt/de_GWD/.repo/nginxConf.zip $sha256sum_nginxConf) = "false" ]]; then +rm -rf /tmp/nginxConf.zip +wget --show-progress -cqO /tmp/nginxConf.zip https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/nginx/nginxConf.zip +[[ $(checkSum /tmp/nginxConf.zip $sha256sum_nginxConf) = "false" ]] && echo -e "${RED}Download Failed${cRES}" && exit +[[ $(checkSum /tmp/nginxConf.zip $sha256sum_nginxConf) = "true" ]] && mv -f /tmp/nginxConf.zip /opt/de_GWD/.repo/nginxConf.zip +fi + +if [[ $(ttyd -v 2>&1 | grep -o '[0-9]\.[0-9]\.[0-9]') != $TTYD_Ver ]]; then +wget --show-progress -cqO /tmp/ttyd https://github.com/tsl0922/ttyd/releases/download/$TTYD_Ver/ttyd.$(uname -m) +[[ $? -ne 0 ]] && echo -e "${WHITE}TTYD${RED} Download Failed${cRES}" +[[ $(du -sk /tmp/ttyd 2>/dev/null | awk '{print$1}') -gt 1000 ]] && mv -f /tmp/ttyd /usr/bin/ttyd && chmod +x /usr/bin/ttyd && TTYD_UPDATE="true" +fi + +if [[ $(checkSum /opt/de_GWD/.repo/client.zip $sha256sum_client) = "false" ]]; then +rm -rf /tmp/client.zip +wget --show-progress -cqO /tmp/client.zip https://raw.githubusercontent.com/jacyl4/de_GWD/$branch/resource/client/Archive.zip +[[ $(checkSum /tmp/client.zip $sha256sum_client) = "false" ]] && echo -e "${WHITE}Client Zip${RED} Download Failed${cRES}" && exit +[[ $(checkSum /tmp/client.zip $sha256sum_client) = "true" ]] && mv -f /tmp/client.zip /opt/de_GWD/.repo/client.zip +fi + +localVer=$(awk 'NR==1' /opt/de_GWD/.repo/version.php 2>/dev/null) +remoteVer=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/de_GWD/main/version.php | head -n 1) + +if [[ $localVer != $remoteVer ]] || [[ ! -f '/opt/de_GWD/.repo/version.php' ]]; then +rm -rf /opt/de_GWD/.repo/version.php +wget --show-progress -cqO /opt/de_GWD/.repo/version.php https://raw.githubusercontent.com/jacyl4/de_GWD/main/version.php +[[ $? -ne 0 ]] && echo -e "${WHITE}Version file${RED} Download Failed${cRES}" && exit +fi + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Repo Download${cRES}" +} + + + +cleanDep(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Clean-up${cRES}\r\c" +service cron stop + +sed -i "/nfsvers/d" /etc/fstab >/dev/null 2>&1 +sed -i '/quic/d' /etc/nginx/conf.d/*.conf >/dev/null 2>&1 + +[[ $(jq '.v2nodeDIV.nodeSM' /opt/de_GWD/0conf) = "[]" ]] && jq '.v2nodeDIV.nodeSM={}' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ $(jq '.v2nodeDIV.nodeDT' /opt/de_GWD/0conf) = "[]" ]] && jq '.v2nodeDIV.nodeDT={}' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ $(jq '.v2nodeDIV.nodeCU' /opt/de_GWD/0conf) = "[]" ]] && jq '.v2nodeDIV.nodeCU={}' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +[[ -n $(jq '.v2nodeDIV.nodeCU.custom' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.v2nodeDIV.nodeCU.custom)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.v2nodeDIV.nodeDT.divert' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.v2nodeDIV.nodeDT.divert)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.v2nodeDIV.nodeDT.ip' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.v2nodeDIV.nodeDT.ip)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.listB' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.listB)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.listW' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.listW)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.listBlan' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.listBlan)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.listWlan' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.listWlan)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.dns.APPLEcn' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.dns.APPLEcn)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.dns.STEAMcn' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.dns.STEAMcn)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.v2nodeDIV.directApple' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.v2nodeDIV.directApple)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $(jq '.v2nodeDIV.directSteam' /opt/de_GWD/0conf | grep -v '^null$') ]] && jq 'del(.v2nodeDIV.directSteam)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +dohORI=$(jq -r '.dns.DOH' /opt/de_GWD/0conf | grep -v '^null$') +dogORI=$(jq -r '.dns.DoG' /opt/de_GWD/0conf | grep -v '^null$') +[[ -n $dohORI ]] && jq --argjson doh "$dohORI" '.dns.doh=$doh' /opt/de_GWD/0conf | jq 'del(.dns.DOH)' | sponge /opt/de_GWD/0conf +[[ -n $dogORI ]] && jq --arg dog "$dogORI" '.dns.dog=$dog' /opt/de_GWD/0conf | jq 'del(.dns.DoG)' | sponge /opt/de_GWD/0conf + +adlists=$(jq -r '.dns.adlistsURL' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +[[ -n $(jq '.[]' <<< "$adlists") ]] && jq --argjson adlists "$adlists" '.dns.adlists=$adlists' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +adBlist=$(jq -r '.dns.adBlistURL' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +[[ -n $(jq '.[]' <<< "$adBlist") ]] && jq --argjson adBlist "$adBlist" '.dns.adBlist=$adBlist' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +adBregex=$(jq -r '.dns.regexRule' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +[[ -n $(jq '.[]' <<< "$adBregex") ]] && jq --argjson adBregex "$adBregex" '.dns.adBregex=$adBregex' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +adWlist=$(jq -r '.dns.adWlistURL' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +[[ -n $(jq '.[]' <<< "$adWlist") ]] && jq --argjson adWlist "$adWlist" '.dns.adWlist=$adWlist' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +jq 'del(.dns.adlistsURL)' /opt/de_GWD/0conf |\ +jq 'del(.dns.regexRule)' |\ +jq 'del(.dns.adWlistURL)' |\ +jq 'del(.dns.adBlistURL)' | sponge /opt/de_GWD/0conf + +[[ -d "/opt/bitwardenrs" ]] && mv -f /opt/bitwardenrs /opt/bitwarden + +if [[ -f "/etc/systemd/system/doh-client.service" ]] || [[ -f "/lib/systemd/system/doh-client.service" ]]; then + systemctl disable --now doh-client >/dev/null 2>&1 + rm -rf /lib/systemd/system/doh-client.service + rm -rf /etc/systemd/system/doh-client.service + rm -rf /opt/de_GWD/doh-client* + rm -rf "/etc/NetworkManager/dispatcher.d" + systemctl daemon-reload >/dev/null +fi + +if [[ -f "/etc/systemd/system/doh-server.service" ]] || [[ -f "/lib/systemd/system/doh-server.service" ]]; then + systemctl disable --now doh-server >/dev/null 2>&1 + rm -rf /lib/systemd/system/doh-server.service + rm -rf /etc/systemd/system/doh-server.service + rm -rf /opt/de_GWD/doh-server* + rm -rf "/etc/NetworkManager/dispatcher.d" + systemctl daemon-reload >/dev/null +fi + +if [[ -f "/etc/systemd/system/iptables-proxy.service" ]] || [[ -f "/lib/systemd/system/iptables-proxy.service" ]]; then + systemctl disable iptables-proxy >/dev/null 2>&1 + rm -rf /etc/systemd/system/iptables-proxy.service >/dev/null 2>&1 + rm -rf /lib/systemd/system/iptables-proxy.service >/dev/null 2>&1 + systemctl daemon-reload >/dev/null + /opt/de_GWD/iptables-proxy-down + rm -rf /opt/de_GWD/iptables-proxy-down + rm -rf /opt/de_GWD/iptables-proxy-up +fi + + +if [[ -d "/opt/de_GWD/xDNSc" ]]; then + systemctl disable xDNSc >/dev/null 2>&1 + systemctl stop xDNSc >/dev/null 2>&1 + rm -rf /etc/systemd/system/xDNSc.service + rm -rf /lib/systemd/system/xDNSc.service + systemctl daemon-reload >/dev/null + rm -rf /opt/de_GWD/xDNSc + jq 'del(.dns.xDNS)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +fi + +if [[ -d "/opt/de_GWD/xDNSs" ]]; then + systemctl disable xDNSs >/dev/null 2>&1 + systemctl stop xDNSs >/dev/null 2>&1 + rm -rf /etc/systemd/system/xDNSs.service + rm -rf /lib/systemd/system/xDNSs.service + systemctl daemon-reload >/dev/null + rm -rf /opt/de_GWD/xDNSs + jq 'del(.FORWARD.xDNSs)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +fi + +if [[ `dpkg -l | grep php | grep fpm | awk '{print $2}'` = "php7.3-fpm" ]] || [[ `dpkg -l | grep php | grep fpm | awk '{print $2}'` = "php8.0-fpm" ]]; then + rm -rf /etc/php/7.3/ + apt remove --purge '^php7.3.*' + rm -rf /etc/php/8.0/ + apt remove --purge '^php8.0.*' +fi + +[[ -f "/etc/nginx/off" ]] && rm -rf /etc/nginx/off +rm -rf /etc/dnsmasq.d/89-bogus-domains.china.conf +rm -rf /etc/dnsmasq.d/89-bogus-nxdomains.china.conf +[[ -n $(dpkg -l | awk '{print$2}' | grep '^smartdns$') ]] && rm -rf /etc/smartdns && apt remove --purge smartdns +[[ -n $(systemctl cat v2dns 2>/dev/null) ]] && systemctl disable --now v2dns >/dev/null 2>&1 && \ +rm -rf /lib/systemd/system/v2dns.service && \ +rm -rf /etc/systemd/system/v2dns.service && \ +rm -rf /opt/de_GWD/v2dns +[[ -n $(dpkg -l | awk '{print$2}' | grep '^haveged$') ]] && apt remove --purge haveged +[[ -n $(dpkg -l | awk '{print$2}' | grep '^subversion$') ]] && apt remove --purge subversion + +rm -rf /etc/pihole/migration_backup +rm -rf /etc/dnsmasq.d/89-bogus-nxdomain.china.conf +rm -rf /etc/apt/sources.list.d/unstable.list +rm -rf /etc/apt/preferences.d/limit-unstable +rm -rf /opt/de_GWD/.repo/vtrui.zip +rm -rf /opt/de_GWD/chnroute.txt +rm -rf /opt/de_GWD/Q4am +rm -rf /opt/de_GWD/Q4H +rm -rf /opt/de_GWD/Q2H +rm -rf /etc/dns-over-https +rm -rf /usr/bin/vtrui +rm -rf /usr/local/bin/yq +rm -rf /usr/sbin/yq +rm -rf /etc/vtrui +rm -rf /opt/de_GWD/ttyd +rm -rf /opt/de_GWD/IPxDNSSET +rm -rf /opt/de_GWD/chnrouteSET +rm -rf /opt/de_GWD/IPGlobalDNSSET +rm -rf /opt/de_GWD/IPlistBlanSET +rm -rf /opt/de_GWD/IPlistBSET +rm -rf /opt/de_GWD/IPlistWlanSET +rm -rf /opt/de_GWD/IPlistWSET +rm -rf /opt/de_GWD/IPv2nodeSET +rm -rf /opt/de_GWD/__MACOSX +rm -rf /opt/de_GWD/clearKernel +rm -rf /var/www/html/__MACOSX +rm -rf /var/log/smartdns.log +rm -rf /etc/dnsmasq.d/00-wg.conf +rm -rf /etc/dnsmasq.d/99-extra.conf +[[ -f "/etc/rc.local" ]] && [[ -n $(grep 'tc qdisc' /etc/rc.local) ]] && rm -rf /etc/rc.local + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Clean-up${cRES}" +} + + + +preUpdate(){ +echo -e "${BLUE}################################################################# ${cRES}" +echo -e "${GREEN}DNS information${cRES}" +echo + +ethernetnum=$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device' | xargs -n 1 | grep -v 'virtual' | grep -v 'ifb' | awk -F'/' '{print$NF}' | head -n1) +gatewayAddr=$(jq -r '.address.upstreamIP' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +localAddrCIDR=$(jq -r '.address.localIP' /opt/de_GWD/0conf | grep -v '^null$') +localAddr=$(echo $localAddrCIDR | cut -d / -f1) +netmask=$(echo $localAddrCIDR | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g') + +if [[ -n $netmask ]]; then +localCIDR="$(echo $localAddr | cut -d . -f1-3).0$netmask" +else +netmask="/24" +localAddrCIDR="$localAddr$netmask" +localCIDR="$(echo $localAddr | cut -d . -f1-3).0$netmask" +fi + +DoG=$(jq -r '.dns.dog' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +doh1=$(jq -r '.dns.doh[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | awk NR==1) +doh2=$(jq -r '.dns.doh[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | awk NR==2) + +[[ -n $doh1 ]] && echo -e "\t${WHITE}DNS over Https 1: \c" && echo -e "${YELLOW}$doh1${cRES}" +[[ -n $doh2 ]] && echo -e "\t${WHITE}DNS over Https 2: \c" && echo -e "${YELLOW}$doh2${cRES}" +[[ -n $DoG ]] && echo -e "\t${WHITE}DNS over gRPC : \c" && echo -e "${YELLOW}$DoG${cRES}" + + +domain=$(jq -r '.update.v2node.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +tls=$(jq -r '.update.v2node.tls' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +port=$(jq -r '.update.v2node.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +uuid=$(jq -r '.update.v2node.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +path=$(jq -r '.update.v2node.path' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +if [[ -z $domain ]] || [[ -z $uuid ]]; then + cp -f /opt/de_GWD/0conf_bak /opt/de_GWD/0conf + clear + preUpdate +fi + +[[ -z $tls ]] && tls=$domain + +piholePW=$(jq -r '.address.PWD' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +serverName=$(jq -r '.address.serverName' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +webUIport=$(jq -r '.address.webUIport' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +updatePort=$(jq -r '.update.updatePort' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +echo +echo -e "${GREEN}Node Information${cRES}" +echo +echo -e "\t${WHITE}Domain : \c" && echo -e "${YELLOW}$domain${cRES}" +echo -e "\t${WHITE}Port : \c" && echo -e "${YELLOW}$port${cRES}" +echo -e "\t${WHITE}UUID : \c" && echo -e "${YELLOW}$uuid${cRES}" +echo -e "\t${WHITE}Path : \c" && echo -e "${YELLOW}$path${cRES}" +echo -e "${BLUE}################################################################# ${cRES}" +echo +} + + + +de_GWDconnect(){ +if [[ $1 = "u" ]]; then +echo -e "${WHITE}de_GWD server connect ${cRES}\c" && echo -e "\t${WHITE}[...]${cRES}\r\c" +else +echo -e "\t${WHITE}de_GWD server connect${cRES}\r\c" +fi + +local serverConnect1=$(curl -Is -m 5 google.com) +local serverConnect2=$(curl -Is -m 5 youtube.com) + +if [[ $1 = "u" ]]; then + if [[ $2 = "a" ]]; then + preDL + updateGWD_Green + [[ -z $serverConnect1 ]] || [[ -z $serverConnect2 ]] && exit + else + if [[ -n $serverConnect1 ]] && [[ -n $serverConnect2 ]] && [[ $(systemctl is-active 'vtrui') = "active" ]]; then + echo -e "${WHITE}de_GWD server connect ${cRES}\c" && echo -e "\t${WHITE}[${GREEN} ✓ ${WHITE}]${cRES}" + de_GWDconnect_check="OK" + echo -e "${GREEN}================================= ${cRES}" + echo -e "${GREEN}[Y]: Full Update${cRES}" + echo -e "${GREEN}[*]: Any other key to Fast Update${cRES}" + echo -e "${GREEN}================================= ${cRES}" + read -s -n 1 updateDebian + echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Start Updating de_GWD${cRES}\r\c" + + if [[ $updateDebian = "Y" ]] || [[ $updateDebian = "y" ]]; then + preDL + updateAPT + fi + preDL + updateGWD_Green + else + echo -e "${WHITE}de_GWD server connect ${cRES}\c" && echo -e "\t${WHITE}[${RED} ✕ ${WHITE}]${cRES}" + updateGWD_Red + fi + fi +else + if [[ -n $serverConnect1 ]] && [[ -n $serverConnect2 ]] && [[ $(systemctl is-active 'vtrui') = "active" ]]; then + echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}de_GWD server connect${cRES}" + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}de_GWD server connect${cRES}" + fi + + +if [[ -z $serverConnect1 ]] || [[ -z $serverConnect2 ]]; then +cat << EOF >/etc/resolv.conf +nameserver 119.29.29.29 +nameserver 180.76.76.76 +nameserver 114.114.114.114 +nameserver 223.5.5.5 +EOF +systemctl stop smartdns >/dev/null 2>&1 +systemctl stop nftables >/dev/null 2>&1 +exit +fi +fi +} + + + +preInstall(){ +sync; echo 3 >/proc/sys/vm/drop_caches >/dev/null 2>&1 + +cat << EOF >/etc/apt/apt.conf.d/01InstallLess +APT::Get::Assume-Yes "true"; +APT::Install-Recommends "false"; +APT::Install-Suggests "false"; +EOF + +cat << EOF >/etc/apt/apt.conf.d/71debconf +Dpkg::Options { + "--force-confdef"; + "--force-confold"; +}; +EOF + +sed -i '/ulimit -SHn/d' /etc/profile +sed -i '/ulimit -c/d' /etc/profile +sed -i '/ulimit -d/d' /etc/profile +sed -i '/ulimit -f/d' /etc/profile +sed -i '/ulimit -m/d' /etc/profile +sed -i '/ulimit -s/d' /etc/profile +sed -i '/ulimit -t/d' /etc/profile +sed -i '/ulimit -u/d' /etc/profile +sed -i '/ulimit -v/d' /etc/profile +sed -i '/HISTCONTROL=/d' /etc/profile +sed -i '/alias reboot=/d' /etc/profile +cat << EOF >>/etc/profile +ulimit -SHn 1000000 +ulimit -c unlimited +ulimit -d unlimited +ulimit -f unlimited +ulimit -m unlimited +ulimit -s unlimited +ulimit -t unlimited +ulimit -u 1000000 +ulimit -v unlimited + +HISTCONTROL=ignoredups +alias reboot="sudo systemctl reboot" +EOF +sed -i '/pam_limits.so/d' /etc/pam.d/common-session +echo "session required pam_limits.so" >>/etc/pam.d/common-session +source /etc/profile + +cat << EOF >/etc/security/limits.conf +root soft nofile 1000000 +root hard nofile 1000000 +root soft nproc 1000000 +root hard nproc 1000000 +root soft core 1000000 +root hard core 1000000 +root hard memlock unlimited +root soft memlock unlimited + +www-data soft nofile 1000000 +www-data hard nofile 1000000 +www-data soft nproc 1000000 +www-data hard nproc 1000000 +www-data soft core 1000000 +www-data hard core 1000000 +www-data hard memlock unlimited +www-data soft memlock unlimited + +* soft nofile 1000000 +* hard nofile 1000000 +* soft nproc 1000000 +* hard nproc 1000000 +* soft core 1000000 +* hard core 1000000 +* hard memlock unlimited +* soft memlock unlimited +EOF + +sed -i '/DefaultLimitCORE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNOFILE/d' /etc/systemd/system.conf +sed -i '/DefaultLimitNPROC/d' /etc/systemd/system.conf +cat << EOF >>/etc/systemd/system.conf +DefaultLimitCORE=1000000 +DefaultLimitNOFILE=1000000 +DefaultLimitNPROC=1000000 +EOF +systemctl daemon-reload + +rm -f /var/cache/apt/archives/lock +rm -f /var/lib/apt/lists/lock +rm -f /var/lib/dpkg/lock +rm -f /var/lib/dpkg/lock-frontend +dpkg --configure -a + +pkgDEP1 + +cat << EOF >/etc/default/rng-tools-debian +# -*- mode: sh -*- +#- +# Configuration for the rng-tools-debian initscript + +# Set to the input source for random data, leave undefined +# for the initscript to attempt auto-detection. Set to /dev/null +# for the viapadlock driver. +#HRNGDEVICE=/dev/hwrng +#HRNGDEVICE=/dev/null +HRNGDEVICE=/dev/urandom + +# Additional options to send to rngd. See the rngd(8) manpage for +# more information. Do not specify -r/--rng-device here, use +# HRNGDEVICE for that instead. +#RNGDOPTIONS="--hrng=intelfwh --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viakernel --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viapadlock --fill-watermark=90% --feed-interval=1" +# For TPM (also add tpm-rng to /etc/initramfs-tools/modules or /etc/modules): +#RNGDOPTIONS="--fill-watermark=90% --feed-interval=1" + +# If you need to configure which RNG to use, do it here: +#HRNGSELECT="virtio_rng.0" +# Use this instead of sysfsutils, which starts too late. +EOF +systemctl restart rng-tools + +cat << EOF >/etc/chrony/chrony.conf +server time.cloud.tencent.com iburst +server time4.cloud.tencent.com iburst +server time5.cloud.tencent.com iburst +server ntp.aliyun.com iburst +server ntp6.aliyun.com iburst +server ntp7.aliyun.com iburst + +driftfile /var/lib/chrony/chrony.drift +logdir /var/log/chrony +maxupdateskew 100.0 +rtcsync +makestep 1 3 +leapsectz right/UTC +EOF +systemctl restart chrony +systemctl enable chrony >/dev/null 2>&1 + +rm -rf /etc/systemd/resolved.conf >/dev/null 2>&1 +systemctl daemon-reload >/dev/null +systemctl mask --now systemd-resolved >/dev/null 2>&1 + +[[ -n $(which setenforce) ]] && setenforce 0 +[[ -f "/etc/selinux/config" ]] && sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config + +ip rule del table 220 >/dev/null 2>&1 +ip route flush table 220 >/dev/null 2>&1 +ip route flush cache >/dev/null 2>&1 +ip route del local default dev lo table 220 >/dev/null 2>&1 + +[[ -n $(systemctl cat nftables 2>/dev/null) ]] && systemctl stop nftables >/dev/null 2>&1 +[[ -n $(systemctl cat vtrui 2>/dev/null) ]] && systemctl stop vtrui >/dev/null 2>&1 + +[[ -n "$(ps -e | grep 'pihole-FTL' )" ]] && systemctl stop pihole-FTL +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 + +cat << EOF >/etc/resolv.conf +nameserver 119.29.29.29 +nameserver 180.76.76.76 +nameserver 114.114.114.114 +nameserver 223.5.5.5 +EOF +} + + + +preConf(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}System Config${cRES}\r\c" +localeSet=`cat << EOF +LANG=en_US.UTF-8 +LANGUAGE=en_US.UTF-8 +LC_CTYPE="en_US.UTF-8" +LC_NUMERIC="en_US.UTF-8" +LC_TIME="en_US.UTF-8" +LC_COLLATE="en_US.UTF-8" +LC_MONETARY="en_US.UTF-8" +LC_MESSAGES="en_US.UTF-8" +LC_PAPER="en_US.UTF-8" +LC_NAME="en_US.UTF-8" +LC_ADDRESS="en_US.UTF-8" +LC_TELEPHONE="en_US.UTF-8" +LC_MEASUREMENT="en_US.UTF-8" +LC_IDENTIFICATION="en_US.UTF-8" +LC_ALL=en_US.UTF-8 +EOF +` +if [[ -z $(localectl list-locales | grep "en_US.UTF-8") ]]; then +echo "$localeSet" >/etc/default/locale +echo "en_US.UTF-8 UTF-8" >/etc/locale.gen +locale-gen "en_US.UTF-8" +localectl set-locale en_US.UTF-8 +update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 +fi + +[[ $(date +"%Z %z") != "CST +0800" ]] && timedatectl set-timezone "Asia/Shanghai" +timedatectl set-local-rtc 0 >/dev/null 2>&1 +timedatectl set-ntp true + +sed -i '/nf_conntrack/d' /etc/modules-load.d/modules.conf +sed -i '/ifb/d' /etc/modules-load.d/modules.conf +cat << EOF >>/etc/modules-load.d/modules.conf +nf_conntrack +ifb +sch_cake +EOF +modprobe nf_conntrack +modprobe ifb +modprobe sch_cake + +cat << EOF >/etc/sysctl.conf +vm.overcommit_memory = 1 +vm.swappiness = 10 +vm.dirty_ratio = 10 +vm.dirty_background_ratio = 5 +fs.nr_open = 1000000 +fs.file-max = 1000000 +fs.inotify.max_user_instances = 819200 +fs.inotify.max_queued_events = 32000 +fs.inotify.max_user_watches = 64000 +net.unix.max_dgram_qlen = 10240 +net.nf_conntrack_max = 131072 +net.netfilter.nf_conntrack_acct = 0 +net.netfilter.nf_conntrack_checksum = 0 +net.netfilter.nf_conntrack_events = 1 +net.netfilter.nf_conntrack_timestamp = 0 +net.netfilter.nf_conntrack_max = 16384 +net.netfilter.nf_conntrack_buckets = 65535 +net.netfilter.nf_conntrack_tcp_loose = 1 +net.netfilter.nf_conntrack_tcp_be_liberal = 1 +net.netfilter.nf_conntrack_tcp_max_retrans = 3 +net.netfilter.nf_conntrack_generic_timeout = 60 +net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 30 +net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 +net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15 +net.netfilter.nf_conntrack_tcp_timeout_close = 5 +net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30 +net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 30 +net.netfilter.nf_conntrack_tcp_timeout_established = 3600 +net.netfilter.nf_conntrack_sctp_timeout_established = 3600 +net.netfilter.nf_conntrack_udp_timeout = 15 +net.netfilter.nf_conntrack_udp_timeout_stream = 45 +net.core.somaxconn = 65535 +net.core.netdev_max_backlog = 262144 +net.core.optmem_max = 8388608 +net.core.rmem_default = 8388608 +net.core.wmem_default = 8388608 +net.core.rmem_max = 33554432 +net.core.wmem_max = 33554432 +net.mptcp.enabled = 1 +net.ipv4.conf.all.arp_accept = 0 +net.ipv4.conf.default.arp_accept = 0 +net.ipv4.conf.all.arp_announce = 2 +net.ipv4.conf.default.arp_announce = 2 +net.ipv4.conf.all.arp_ignore = 1 +net.ipv4.conf.default.arp_ignore = 1 +net.ipv4.conf.all.rp_filter = 0 +net.ipv4.conf.default.rp_filter = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.secure_redirects = 0 +net.ipv4.conf.default.secure_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv4.conf.all.route_localnet = 1 +net.ipv4.route.flush = 1 +net.ipv4.ip_local_port_range = 1024 65535 +net.ipv4.ip_local_reserved_ports = 3000 +net.ipv4.ip_forward = 1 +net.ipv4.conf.all.forwarding = 1 +net.ipv4.conf.default.forwarding = 1 +net.ipv4.ip_no_pmtu_disc = 0 +net.ipv4.udp_rmem_min = 262144 +net.ipv4.udp_wmem_min = 262144 +net.ipv4.tcp_mem = 8388608 8388608 8388608 +net.ipv4.tcp_rmem = 8192 262144 16777216 +net.ipv4.tcp_wmem = 8192 262144 16777216 +net.ipv4.tcp_max_tw_buckets = 131072 +net.ipv4.tcp_max_orphans = 131072 +net.ipv4.tcp_max_syn_backlog = 32768 +net.ipv4.tcp_limit_output_bytes = 1048576 +net.ipv4.tcp_adv_win_scale = 1 +net.ipv4.tcp_moderate_rcvbuf = 1 +net.ipv4.tcp_window_scaling = 1 +net.ipv4.tcp_workaround_signed_windows = 0 +net.ipv4.tcp_mtu_probing = 0 +net.ipv4.tcp_mtu_probe_floor = 48 +net.ipv4.tcp_base_mss = 1024 +net.ipv4.tcp_no_metrics_save = 0 +net.ipv4.tcp_no_ssthresh_metrics_save = 1 +net.ipv4.tcp_available_ulp = espintcp mptcp +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_dsack = 1 +net.ipv4.tcp_frto = 0 +net.ipv4.tcp_recovery = 1 +net.ipv4.tcp_early_retrans = 3 +net.ipv4.tcp_min_rtt_wlen = 120 +net.ipv4.tcp_reordering = 3 +net.ipv4.tcp_ecn = 0 +net.ipv4.tcp_fin_timeout = 10 +net.ipv4.tcp_fastopen = 3 +net.ipv4.tcp_fastopen_blackhole_timeout_sec = 0 +net.ipv4.tcp_fastopen_key = 00000000-00000000-00000000-00000000 +net.ipv4.tcp_keepalive_time = 7200 +net.ipv4.tcp_keepalive_intvl = 75 +net.ipv4.tcp_keepalive_probes = 9 +net.ipv4.tcp_timestamps = 0 +net.ipv4.tcp_syncookies = 0 +net.ipv4.tcp_tw_reuse = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_retries1 = 3 +net.ipv4.tcp_retries2 = 8 +net.ipv4.tcp_orphan_retries = 0 +net.ipv4.tcp_challenge_ack_limit = 100000 +net.ipv4.tcp_slow_start_after_idle = 0 +net.ipv4.tcp_autocorking = 0 +net.ipv4.tcp_rfc1337 = 1 +net.core.default_qdisc = cake +EOF + +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf +if [[ $(uname -r) =~ "bbrplus" ]]; then + echo "net.ipv4.tcp_congestion_control = bbrplus" >>/etc/sysctl.conf +else + echo "net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.conf +fi +sysctl -p >/dev/null 2>&1 + +if [[ -n $(dpkg -l | awk '{print$2}' | grep '^docker-ce$') ]] && [[ -n $(dpkg -l | awk '{print$2}' | grep '^containerd.io$') ]]; then +mkdir -p /etc/docker/ +systemctl stop docker docker.socket containerd +cat << EOF >/etc/docker/daemon.json +{ + "iptables": false +} +EOF +systemctl restart docker +fi + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}System Config${cRES}" +} + + + +installSmartDNS(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Proxy Components Prepared${cRES}\r\c" +if [[ -n $(unzip -tq /opt/de_GWD/.repo/de_GWD.zip | grep "No errors detected in compressed data") ]]; then +rm -rf /opt/de_GWD/smartdns +rm -rf /opt/de_GWD/coredns +rm -rf /opt/de_GWD/mosdns +rm -rf /opt/de_GWD/vtrui +mkdir -p /opt/de_GWD/smartdns +mkdir -p /opt/de_GWD/coredns +mkdir -p /opt/de_GWD/mosdns +mkdir -p /opt/de_GWD/vtrui + +rm -rf /tmp/de_GWD +unzip /opt/de_GWD/.repo/de_GWD.zip -d /tmp/de_GWD >/dev/null +cp -f /tmp/de_GWD/yq /usr/bin/yq +cp -f /tmp/de_GWD/smartdns /opt/de_GWD/smartdns/smartdns +cp -f /tmp/de_GWD/coredns /opt/de_GWD/coredns/coredns +cp -f /tmp/de_GWD/mosdns /opt/de_GWD/mosdns/mosdns +cp -f /tmp/de_GWD/xray /opt/de_GWD/vtrui/vtrui +chmod +x /usr/bin/yq +chmod +x /opt/de_GWD/smartdns/smartdns +chmod +x /opt/de_GWD/coredns/coredns +chmod +x /opt/de_GWD/mosdns/mosdns +chmod +x /opt/de_GWD/vtrui/vtrui +rm -rf /tmp/de_GWD* +else +rm -rf /opt/de_GWD/.repo/de_GWD.zip +echo -e "${WHITE}de_GWD Zip${RED} Download Failed${cRES}" && exit +fi +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Proxy Components prepared${cRES}" + + + +rm -rf /lib/systemd/system/coredns.service +cat << EOF >/etc/systemd/system/coredns.service +[Unit] +Description=CoreDNS DNS server +After=network.target + +[Service] +User=root +Type=simple +ExecStart=/opt/de_GWD/coredns/coredns -conf /opt/de_GWD/coredns/corefile +ExecReload=$(which kill) -SIGUSR1 \$MAINPID +KillMode=process +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null + + +mkdir -p /var/log/smartdns +>/var/log/smartdns/smartdns.log +cat << EOF >/opt/de_GWD/smartdns/smartdns.conf +bind :53 -group DNS_global + +bind 127.0.0.1:5331 -no-speed-check -no-cache -group DNS_chn +bind-tcp 127.0.0.1:5331 -no-speed-check -no-cache -group DNS_chn + +bind 127.0.0.1:5332 -no-speed-check -no-cache -group DNS_global +bind-tcp 127.0.0.1:5332 -no-speed-check -no-cache -group DNS_global + +server 114.114.114.114 -group DNS_chn -exclude-default-group +server 114.114.115.115 -group DNS_chn -exclude-default-group +server 119.29.29.29 -group DNS_chn -exclude-default-group +server 119.28.28.28 -group DNS_chn -exclude-default-group +server 180.76.76.76 -group DNS_chn -exclude-default-group +server 223.5.5.5 -group DNS_chn -exclude-default-group +server 223.6.6.6 -group DNS_chn -exclude-default-group +EOF + +kill -9 $(ps -e | grep 'smartdns' | awk '{print$1}') >/dev/null 2>&1 +rm -rf /lib/systemd/system/smartdns.service +cat << EOF >/etc/systemd/system/smartdns.service +[Unit] +Description=SmartDNS +After=network.target + +[Service] +User=root +Type=forking +PIDFile=/run/smartdns.pid +ExecStart=/opt/de_GWD/smartdns/smartdns -p /run/smartdns.pid -c /opt/de_GWD/smartdns/smartdns.conf +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +Nice=-12 + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl restart smartdns +if [[ $? -ne 0 ]]; then +sed -i '/Nice=/d' /etc/systemd/system/smartdns.service +systemctl daemon-reload >/dev/null +systemctl restart smartdns +fi +systemctl enable smartdns >/dev/null 2>&1 + +rm -rf /etc/resolvconf/resolv.conf.d/* +>/etc/resolvconf/resolv.conf.d/original +>/etc/resolvconf/resolv.conf.d/base +>/etc/resolvconf/resolv.conf.d/tail +rm -rf /etc/resolv.conf +rm -rf /run/resolvconf/interface +cat << EOF >/etc/resolvconf/resolv.conf.d/head +nameserver 127.0.0.1 +EOF +if [[ -f "/etc/resolvconf/run/resolv.conf" ]]; then +ln -sf /etc/resolvconf/run/resolv.conf /etc/resolv.conf +elif [[ -f "/run/resolvconf/resolv.conf" ]]; then +ln -sf /run/resolvconf/resolv.conf /etc/resolv.conf +fi +sed -i '/dns-nameservers /d' /etc/network/interfaces +resolvconf -u + + + +echo +echo -e "${BLUE}################################################################# ${cRES}" +echo + +if [[ -n $doh1 ]]; then +echo -e "${WHITE}DNS over Https 1:\t${cRES}" +echo -e "${WHITE}Domain: \c" && echo -e "\t${WHITE}IP: ${cRES}\r\c" +doh1Domain=$(echo $doh1 | cut -d/ -f1 | cut -d: -f1) +doh1IP=$(dig @127.0.0.1 $doh1Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) + +if [[ -n $doh1IP ]]; then +doh1Port=$(echo $doh1 | cut -d/ -f1 | cut -d: -f2 | grep '^[[:digit:]]*$') +doh1Path=$(echo $doh1 | cut -d/ -f2) + +if [[ -z $doh1Port ]]; then + doh1Str="$doh1IP/$doh1Path" +else + doh1Str="$doh1IP:$doh1Port/$doh1Path" +fi + +cat << EOF >>/opt/de_GWD/smartdns/smartdns.conf +server-https https://$doh1Str -host-name $doh1Domain -no-check-certificate -group DNS_global +EOF +fi + +echo -e "${WHITE}Domain: ${YELLOW}$doh1Domain\c" && echo -e "\t${WHITE}IP: ${YELLOW}$doh1IP${cRES}" +echo +fi + +if [[ -n $doh2 ]]; then +echo -e "${WHITE}DNS over Https 2: ${cRES}" +echo -e "${WHITE}Domain: \c" && echo -e "\t${WHITE}IP: ${cRES}\r\c" +doh2Domain=$(echo $doh2 | cut -d/ -f1 | cut -d: -f1) +doh2IP=$(dig @127.0.0.1 $doh2Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) + +if [[ -n $doh2IP ]]; then +doh2Port=$(echo $doh2 | cut -d/ -f1 | cut -d: -f2 | grep '^[[:digit:]]*$') +doh2Path=$(echo $doh2 | cut -d/ -f2) + +if [[ -z $doh2Port ]]; then + doh2Str="$doh2IP/$doh2Path" +else + doh2Str="$doh2IP:$doh2Port/$doh2Path" +fi + +cat << EOF >>/opt/de_GWD/smartdns/smartdns.conf +server-https https://$doh2Str -host-name $doh2Domain -no-check-certificate -group DNS_global +EOF +fi + +echo -e "${WHITE}Domain: ${YELLOW}$doh2Domain\c" && echo -e "\t${WHITE}IP: ${YELLOW}$doh2IP${cRES}" +echo +fi + +if [[ -n $DoG ]]; then +echo -e "${WHITE}DNS over gRPC: ${cRES}" +echo -e "${WHITE}Domain: \c" && echo -e "\t${WHITE}IP: ${cRES}\r\c" +DoGcDomain=$(echo $DoG | cut -d: -f1) +DoGcIP=$(dig @127.0.0.1 $DoGcDomain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +DoGcPort=$(echo $DoG | cut -d: -f2 | grep '^[[:digit:]]*$') +echo -e "${WHITE}Domain: ${YELLOW}$DoGcDomain\c" && echo -e "\t${WHITE}IP: ${YELLOW}$DoGcIP${cRES}" +echo + +cat << EOF >>/opt/de_GWD/smartdns/smartdns.conf +server 127.0.0.1:5333 -group DNS_global +EOF +fi + +systemctl restart smartdns + +if [[ -n $DoGcIP ]]; then +cat << EOF >/opt/de_GWD/coredns/corefile +# DoGc_START +.:5333 { +bind 127.0.0.1 +grpc . $DoGcIP:$DoGcPort { + tls_servername $DoGcDomain +} +template ANY AAAA { + rcode NXDOMAIN +} +reload 6s 3s +} +# DoGc_END +EOF +systemctl enable coredns >/dev/null 2>&1 +systemctl restart coredns +fi + +echo -e "${WHITE}V2 node: ${cRES}" +echo -e "${WHITE}Domain: \c" && echo -e "\t${WHITE}IP: ${cRES}\r\c" +domainIP=$(dig @127.0.0.1 $domain -4p 5332 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +echo -e "${WHITE}Domain: ${YELLOW}$domain\c" && echo -e "\t${WHITE}IP: ${YELLOW}$domainIP${cRES}" +echo +echo -e "${BLUE}################################################################# ${cRES}" +echo +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Deploy SmartDNS${cRES}" + +[[ -z $domainIP ]] && echo -e "${WHITE}V2 node${RED} Failure to resolve${cRES}" && exit + +rm -rf /lib/systemd/system/mosdns.service +cat << EOF >/etc/systemd/system/mosdns.service +[Unit] +Description=mosdns +ConditionFileIsExecutable=/opt/de_GWD/mosdns/mosdns + +[Service] +User=root +Type=simple +ExecStart=/opt/de_GWD/mosdns/mosdns start --as-service -d /opt/de_GWD/mosdns +ExecStop=$(which kill) -s STOP \$MAINPID +KillMode=process +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +Nice=-11 + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +} + + + +installXray(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Deploy vtrui${cRES}\r\c" + +cat << EOF >/opt/de_GWD/vtrui/config.json +{ + "log": { + "access":"none", + "error":"none", + "loglevel":"none" + }, + "dns":{ + "queryStrategy":"UseIP", + "disableCache":true, + "hosts":{"$domain":"$domainIP"}, + "servers":["tcp+local://127.0.0.1:5332"] + }, + "inbounds":[ + { + "port":9896, + "listen":"127.0.0.1", + "protocol":"dokodemo-door", + "settings":{"network":"tcp,udp","followRedirect":true}, + "streamSettings":{"sockopt":{"tcpFastOpen":true,"tproxy":"tproxy","mark":255}} + } + ], + "outbounds":[ + { + "tag":"default" + }, + { + "tag":"direct", + "protocol":"freedom", + "streamSettings":{"sockopt":{"mark":255}} + } + ] +} +EOF + +if [[ -z $path ]]; then +OBdefault=`cat << EOF + { + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } + } +EOF +` +else +OBdefault=`cat << EOF +{ + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "path": "$path", + "headers": { + "Host": "$tls" + } + }, + "security": "tls", + "tlsSettings": { + "serverName": "$tls", + "allowInsecure": false + }, + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } +} +EOF +` +fi + +jq --argjson OBdefault "$OBdefault" '.outbounds[0]=$OBdefault' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + +rm -rf /lib/systemd/system/vtrui.service +cat << EOF >/etc/systemd/system/vtrui.service +[Unit] +Description=vtrui +After=network.target nss-lookup.target + +[Service] +User=root +ExecStart=/opt/de_GWD/vtrui/vtrui run -confdir /opt/de_GWD/vtrui +Restart=on-failure +RestartPreventExitStatus=23 + +Nice=-9 +AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl restart vtrui +if [[ $? -ne 0 ]]; then +sed -i '/Nice=/d' /etc/systemd/system/vtrui.service +systemctl daemon-reload >/dev/null +systemctl restart vtrui +fi +systemctl enable vtrui >/dev/null 2>&1 + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Deploy vtrui${cRES}" +} + + + +installNftables(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Deploy nftables${cRES}\r\c" +cat << EOF >/etc/network/interfaces +source /etc/network/interfaces.d/* + +auto lo +iface lo inet loopback + +auto $ethernetnum +iface $ethernetnum inet static + address $localAddrCIDR + gateway $gatewayAddr +EOF + +rm -rf /etc/nftables* +rm -rf /opt/de_GWD/nftables +mkdir -p /opt/de_GWD/nftables +echo $DoGcIP $doh1IP $doh2IP | xargs -n1 | sort | uniq | sed 's/$/,/g' >/opt/de_GWD/nftables/IP_GlobalDNS +cat << EOF >/opt/de_GWD/nftables/SET_GlobalDNS.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set GlobalDNS { + type ipv4_addr + flags interval + auto-merge + elements = { $(cat /opt/de_GWD/nftables/IP_GlobalDNS) } + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_GlobalDNS.nft +/opt/de_GWD/nftables/SET_GlobalDNS.nft + +cat << EOF >/opt/de_GWD/nftables/SET_V2NODE.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set V2NODE { + type ipv4_addr + flags interval + auto-merge + elements = { $domainIP } + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_V2NODE.nft +/opt/de_GWD/nftables/SET_V2NODE.nft + +if [[ $(du -sk /opt/de_GWD/.repo/IPchnroute 2>/dev/null | awk '{print$1}') -gt 100 ]]; then +cp -f /opt/de_GWD/.repo/IPchnroute /opt/de_GWD/nftables/IP_CHNROUTE +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_CHNROUTE +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_CHNROUTE +fi + +[[ -n $(cat /opt/de_GWD/nftables/IP_CHNROUTE 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_CHNROUTE_elements="elements = { $(cat /opt/de_GWD/nftables/IP_CHNROUTE) }" +cat << EOF >/opt/de_GWD/nftables/SET_CHNROUTE.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set CHNROUTE { + type ipv4_addr + flags interval + auto-merge + $IP_CHNROUTE_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_CHNROUTE.nft +/opt/de_GWD/nftables/SET_CHNROUTE.nft + +[[ -n $(cat /opt/de_GWD/nftables/IP_listB 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listB_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listB) }" +cat << EOF >/opt/de_GWD/nftables/SET_listB.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listB { + type ipv4_addr + flags interval + auto-merge + $IP_listB_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listB.nft +/opt/de_GWD/nftables/SET_listB.nft + +[[ -n $(cat /opt/de_GWD/nftables/IP_listW 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listW_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listW) }" +cat << EOF >/opt/de_GWD/nftables/SET_listW.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listW { + type ipv4_addr + flags interval + auto-merge + $IP_listW_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listW.nft +/opt/de_GWD/nftables/SET_listW.nft + +[[ -n $(cat /opt/de_GWD/nftables/IP_listBlan 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listBlan_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listBlan) }" +cat << EOF >/opt/de_GWD/nftables/SET_listBlan.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listBlan { + type ipv4_addr + flags interval + auto-merge + $IP_listBlan_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listBlan.nft +/opt/de_GWD/nftables/SET_listBlan.nft + +[[ -n $(cat /opt/de_GWD/nftables/IP_listWlan 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listWlan_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listWlan) }" +cat << EOF >/opt/de_GWD/nftables/SET_listWlan.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listWlan { + type ipv4_addr + flags interval + auto-merge + $IP_listWlan_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listWlan.nft +/opt/de_GWD/nftables/SET_listWlan.nft + + +cat << "EOF" >/opt/de_GWD/nftables/flowtable_eth.sh +#!/bin/bash +unset interface_FT +interface_all=$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device') +interface_FT=(${interface_FT[@]} $(echo $interface_all | xargs -n1 | grep -v 'virtual' | awk -F'/' '{print$NF}')) +interface_FT=(${interface_FT[@]} $(echo $interface_all | xargs -n1 | awk -F'/' '{print$NF}' | grep '^docker')) +interface_FT=(${interface_FT[@]} $(echo $interface_all | xargs -n1 | awk -F'/' '{print$NF}' | grep '^wg')) +interface_FT=(${interface_FT[@]} $(echo $interface_all | xargs -n1 | awk -F'/' '{print$NF}' | grep '^ifb4')) +ethernet_FT=$(echo ${interface_FT[@]} | sed -e 's/[ ]/, /g') +echo "define flowtable_eth = { $ethernet_FT }" >/opt/de_GWD/nftables/flowtable.eth +EOF +chmod +x /opt/de_GWD/nftables/flowtable_eth.sh + +cat << EOF >/opt/de_GWD/nftables/default.nft +#!/usr/sbin/nft -f + +include "/opt/de_GWD/nftables/flowtable.eth" + +table inet filter { + flowtable Acceleration { + hook ingress priority 0 + devices = \$flowtable_eth + } + chain INPUT { + type filter hook input priority 0; policy accept; + iifname ifb4lo accept + iifname lo accept + ct state established,related accept + tcp flags != syn ct state new drop + tcp flags & (fin|syn) == (fin|syn) drop + tcp flags & (syn|rst) == (syn|rst) drop + tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) drop + tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) drop + ct state invalid counter drop + # Drop 53 in + } + chain FORWARD { + type filter hook forward priority 0; policy accept; + counter packets 0 bytes 0 + ip protocol { tcp, udp } flow offload @Acceleration + tcp flags & (syn|rst) == syn counter tcp option maxseg size set 1440 + # WireGuard traffic + iifname "ifb4wg0" accept + iifname "wg0" accept + oifname "wg0" accept + + # Docker traffic + counter jump DOCKER-USER + counter jump DOCKER-ISOLATION-STAGE-1 + oifname "docker0" ct state established,related counter accept + oifname "docker0" counter jump DOCKER + iifname "ifb4docker0" oifname != "docker0" counter accept + iifname "ifb4docker0" oifname "docker0" counter accept + iifname "docker0" oifname != "docker0" counter accept + iifname "docker0" oifname "docker0" counter accept + } + chain OUTPUT { + type filter hook output priority 0; policy accept; + } + chain DOCKER { + } + chain DOCKER-USER { + counter accept + } + chain DOCKER-ISOLATION-STAGE-1 { + iifname "ifb4docker0" oifname != "docker0" counter jump DOCKER-ISOLATION-STAGE-2 + iifname "docker0" oifname != "docker0" counter jump DOCKER-ISOLATION-STAGE-2 + counter accept + } + chain DOCKER-ISOLATION-STAGE-2 { + oifname "docker0" counter drop + counter accept + } +} + +table inet router { + chain PREROUTING { + type nat hook prerouting priority -100; policy accept; + # Docker + fib daddr type local counter jump DOCKER + } + chain POSTROUTING { + type nat hook postrouting priority -100; policy accept; + # Wireguard masquerade traffic + oifname $ethernetnum ip saddr 172.16.66.0/24 masquerade + + # Docker + oifname != "docker0" ip saddr 172.17.0.0/16 counter masquerade + } + chain INPUT { + type nat hook input priority -100; policy accept; + } + chain OUTPUT { + type nat hook output priority -100; policy accept; + ip daddr != 127.0.0.0/8 fib daddr type local counter jump DOCKER + } + chain DOCKER { + iifname "ifb4docker0" counter accept + iifname "docker0" counter accept + } +} +EOF +chmod +x /opt/de_GWD/nftables/default.nft + +cat << EOF >/opt/de_GWD/nftables/nftables +#!/usr/sbin/nft -f + +include "/opt/de_GWD/nftables/*.nft" + +define RESERVED_IP = { + $localCIDR, + 10.0.0.0/8, + 100.64.0.0/10, + 127.0.0.0/8, + 169.254.0.0/16, + 172.16.0.0/12, + 192.0.0.0/24, + 192.168.0.0/16, + 224.0.0.0/4, + 240.0.0.0/4, + 255.255.255.255/32, + 114.114.114.114/32, + 114.114.115.115/32, + 119.29.29.29/32, + 119.28.28.28/32, + 180.76.76.76/32, + 223.5.5.5/32, + 223.6.6.6/32 +} + +table ip de_GWD { + set CHNROUTE { + type ipv4_addr + flags interval + auto-merge + } + set GlobalDNS { + type ipv4_addr + flags interval + auto-merge + } + set V2NODE { + type ipv4_addr + flags interval + auto-merge + } + set listB { + type ipv4_addr + flags interval + auto-merge + } + set listW { + type ipv4_addr + flags interval + auto-merge + } + set listBlan { + type ipv4_addr + flags interval + auto-merge + } + set listWlan { + type ipv4_addr + flags interval + auto-merge + } + chain prerouting { + type filter hook prerouting priority -310; policy accept; + meta l4proto { udp } th dport 67 accept + meta l4proto { udp } th dport 1900 accept + meta l4proto { tcp } th dport 2195 accept + meta l4proto { tcp } th dport 2196 accept + meta l4proto { tcp } th dport 2197 accept + meta l4proto { tcp } th dport 3689 accept + meta l4proto { tcp } th dport 5223 accept + meta l4proto { tcp } th dport 5297 accept + meta l4proto { udp } th dport 5350 accept + meta l4proto { udp } th dport 5351 accept + meta l4proto { udp } th dport 5353 accept + ip daddr @GlobalDNS accept + ip saddr @listBlan meta l4proto { tcp, udp } tproxy to 127.0.0.1:9896 meta mark set 0x9 + ip saddr @listWlan accept + ip daddr \$RESERVED_IP accept + ip daddr @listB meta l4proto { tcp, udp } tproxy to 127.0.0.1:9896 meta mark set 0x9 + ip daddr @listW accept + ip daddr @V2NODE accept + ip daddr @CHNROUTE accept + ip protocol { tcp, udp } tproxy to 127.0.0.1:9896 meta mark set 0x9 + } + chain output { + type route hook output priority -311; policy accept; + meta l4proto { udp } th dport 67 accept + meta l4proto { udp } th dport 1900 accept + meta l4proto { tcp } th dport 2195 accept + meta l4proto { tcp } th dport 2196 accept + meta l4proto { tcp } th dport 2197 accept + meta l4proto { tcp } th dport 3689 accept + meta l4proto { tcp } th dport 5223 accept + meta l4proto { tcp } th dport 5297 accept + meta l4proto { udp } th dport 5350 accept + meta l4proto { udp } th dport 5351 accept + meta l4proto { udp } th dport 5353 accept + meta mark 0xff accept + ip daddr @GlobalDNS accept + ip daddr \$RESERVED_IP accept + ip daddr @listB meta mark set 0x9 + ip daddr @listW accept + ip daddr @V2NODE accept + ip daddr @CHNROUTE accept + ip protocol { tcp, udp } meta mark set 0x9 + } +} +EOF +chmod +x /opt/de_GWD/nftables/nftables + +rm -rf /lib/systemd/system/nftables.service +cat << EOF >/etc/systemd/system/nftables.service +[Unit] +Description=nftables +Wants=network-pre.target +Before=network-pre.target shutdown.target +Conflicts=shutdown.target +DefaultDependencies=no + +[Service] +Type=oneshot +RemainAfterExit=yes +StandardInput=null +ProtectSystem=full +ProtectHome=true +ExecStartPre=/bin/bash -c '/opt/de_GWD/nftables/flowtable_eth.sh' +ExecStart=/usr/sbin/nft -f /opt/de_GWD/nftables/nftables ; $(which ip) route add local default dev lo scope host table 220 ; $(which ip) rule add fwmark 0x9 table 220 prio 100 +ExecStop=/usr/sbin/nft flush ruleset ; $(which ip) rule del table 220 ; $(which ip) route del local default dev lo table 220 + +[Install] +WantedBy=sysinit.target +EOF +systemctl daemon-reload >/dev/null +systemctl enable nftables >/dev/null 2>&1 +systemctl restart nftables + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Deploy nftables${cRES}" +} + + + +updateAPT(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Debian Updated${cRES}\r\c" +cat << EOF >/etc/apt/sources.list +deb http://deb.debian.org/debian bookworm main non-free-firmware +deb-src http://deb.debian.org/debian bookworm main non-free-firmware + +deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware +deb-src http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware + +deb http://deb.debian.org/debian bookworm-updates main non-free-firmware +deb-src http://deb.debian.org/debian bookworm-updates main non-free-firmware + +deb http://deb.debian.org/debian bookworm-backports main non-free-firmware +deb-src http://deb.debian.org/debian bookworm-backports main non-free-firmware +EOF + +echo "deb https://packages.sury.org/php/ $(cat /etc/os-release | grep VERSION= | cut -d'(' -f2 | cut -d')' -f1) main" >/etc/apt/sources.list.d/php.list +apt-key del 95BD4743 >/dev/null 2>&1 +wget --no-check-certificate -cqO /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg +[[ $? -ne 0 ]] && echo -e "${WHITE}PHP apt key${RED} Download Failed${cRES}" + +apt update --fix-missing && apt upgrade --allow-downgrades -y +apt full-upgrade -y && apt autoremove --purge -y && apt clean -y && apt autoclean -y + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Debian ${GREEN}Updated${cRES}" +} + + + +installDep(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Dependencies${cRES}\r\c" +sed -i "/www-data/d" /etc/sudoers +sed -i "/Allow members of group sudo to execute any command/a\www-data ALL=(root) NOPASSWD:ALL" /etc/sudoers + +pkgDEP1 + +pkgDEP2 + +>/etc/ld.so.preload +sed -i "/$(uname -m)-linux-gnu/d" /etc/ld.so.conf +ldconfig + + + +if [[ -z $(dpkg -l | awk '{print$2}' | grep '^lighttpd-mod-deflate$') ]]; then +[[ $(printf '%s\n' $(lighttpd -v 2>&1 | grep -Po '(\d+\.)+\d+') "1.4.42" | sort -rV | head -n 1) != "1.4.42" ]] && apt install lighttpd-mod-deflate +fi + +DPKGclean=$(dpkg --list | grep "^rc" | cut -d " " -f 3) +[[ -n $DPKGclean ]] && echo $DPKGclean | xargs sudo dpkg --purge + +rm -rf /var/log/journal/* +systemctl restart systemd-journald >/dev/null 2>&1 + +if [[ -d "/usr/local/ioncube" ]]; then +echo "zend_extension = /usr/local/ioncube/ioncube_loader_lin_7.4.so" >/etc/php/7.4/mods-available/ioncube.ini +ln -sf /etc/php/7.4/mods-available/ioncube.ini /etc/php/7.4/fpm/conf.d/00-ioncube.ini +ln -sf /etc/php/7.4/mods-available/ioncube.ini /etc/php/7.4/cli/conf.d/00-ioncube.ini +fi + +sed -i "/zend_extension/d" /etc/php/7.4/cli/php.ini +sed -i "/zend_extension/d" /etc/php/7.4/fpm/php.ini +sed -i "s/^opcache/;&/" /etc/php/7.4/cli/php.ini +sed -i "s/^opcache/;&/" /etc/php/7.4/fpm/php.ini + +cat << EOF >/etc/php/00-init.ini +expose_php = Off +error_reporting = E_ALL & ~E_NOTICE +display_errors = Off +display_startup_errors = Off +log_errors = On +ignore_repeated_errors = Off + +allow_url_fopen = On +allow_url_include = Off +variables_order = "GPCS" +allow_webdav_methods = On +memory_limit = 128M +max_execution_time = 1200 +max_input_time = 30 +max_input_vars = 5000 +output_buffering = Off +output_handler = "" +zlib.output_compression = Off +zlib.output_handler = "" +safe_mode = Off +register_globals = Off +magic_quotes_gpc = Off +date.timezone = "Asia/Shanghai" + +file_uploads = On +upload_tmp_dir = "/tmp/" +upload_max_filesize = 20M +post_max_size = 20M + +engine = off +enable_dl = Off +disable_functions = "" +disable_classes = "" + +session.save_handler = files +session.use_cookies = 1 +session.use_only_cookies = 1 +session.auto_start = 0 +session.cookie_lifetime = 0 +session.cookie_httponly = 1 +session.cookie_secure = 1 +EOF +ln -sf /etc/php/00-init.ini /etc/php/7.4/cli/conf.d/00-init.ini +ln -sf /etc/php/00-init.ini /etc/php/7.4/fpm/conf.d/00-init.ini + +rm -rf /etc/php/7.4/fpm/pool.d +cat << EOF >/etc/php/7.4/fpm/php-fpm.conf +[global] +pid = /run/php/php7.4-fpm.pid +error_log = /var/log/php.log + +[www] +user = www-data +group = www-data +listen.owner = www-data +listen.group = www-data +listen.mode = 0666 +listen = /run/php/php7.4-fpm.sock +listen.backlog = -1 +listen.allowed_clients = 127.0.0.1 + +pm = dynamic +pm.max_children = 30 +pm.start_servers = 10 +pm.min_spare_servers = 5 +pm.max_spare_servers = 20 +pm.max_requests = 500 +request_terminate_timeout = 300 +request_slowlog_timeout = 0 + +env[HOSTNAME] = \$HOSTNAME +env[PATH] = /usr/local/bin:/usr/bin:/bin +env[TMP] = /tmp +env[TEMP] = /tmp +env[TMPDIR] = /tmp +EOF + +cat << EOF >/etc/php/7.4/mods-available/opcache.ini +; configuration for php opcache module +; priority=10 +zend_extension=opcache.so +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit = off +opcache.jit_buffer_size=128M +opcache.memory_consumption=128 +opcache.interned_strings_buffer=8 +opcache.max_accelerated_files=4000 +opcache.validate_timestamps=1 +opcache.revalidate_freq=60 +opcache.fast_shutdown=1 +opcache.save_comments=1 +EOF + +rm -rf /var/log/php.log +rm -rf /run/php7.4-fpm.pid +rm -rf /lib/systemd/system/php7.4-fpm.service +cat << EOF >/etc/systemd/system/php7.4-fpm.service +[Unit] +Description=The PHP 7.4 FastCGI Process Manager +After=network.target + +[Service] +Type=simple +PIDFile=/run/php7.4-fpm.pid +ExecStartPre=/usr/bin/touch /var/log/php.log +ExecStart=/usr/sbin/php-fpm7.4 --nodaemonize --fpm-config /etc/php/7.4/fpm/php-fpm.conf +ExecReload=$(which kill) -USR2 \$MAINPID +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl enable php7.4-fpm >/dev/null 2>&1 +systemctl restart php7.4-fpm + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Dependencies${cRES}" +} + + + +installNginx(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Nginx${cRES}\r\c" +mkdir -p "/var/www/html" +mkdir -p "/var/www/ssl" +mkdir -p "/etc/nginx" +mkdir -p "/etc/nginx/conf.d" +mkdir -p "/etc/nginx/stream.d" +mkdir -p "/var/log/nginx" +mkdir -p "/var/cache/nginx/client_temp" +mkdir -p "/var/cache/nginx/proxy_temp" +mkdir -p "/var/cache/nginx/fastcgi_temp" +mkdir -p "/var/cache/nginx/scgi_temp" +mkdir -p "/var/cache/nginx/uwsgi_temp" + +if [[ -n $(unzip -tq /opt/de_GWD/.repo/nginxConf.zip | grep "No errors detected in compressed data") ]]; then +rm -rf /tmp/nginxConf +find /etc/nginx/ -type f | grep -v "conf.d" | grep -v "stream.d" | xargs -i rm {} +unzip /opt/de_GWD/.repo/nginxConf.zip -d /etc/nginx >/dev/null +rm -rf /tmp/nginxConf +else +rm -rf /opt/de_GWD/.repo/nginxConf.zip +echo -e "${WHITE}NGINX Configure${RED} Download Failed${cRES}" && exit +fi + +rm -rf /tmp/nginx +rm -rf /lib/systemd/system/nginx.service +cat << EOF >/etc/systemd/system/nginx.service +[Unit] +Description=NGINX +After=network.target + +[Service] +Type=forking +PIDFile=/run/nginx.pid +ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf +ExecReload=/usr/sbin/nginx -s reload +ExecStop=$(which kill) -s QUIT \$MAINPID +KillMode=process +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +[Install] +WantedBy=multi-user.target +EOF +mkdir -p "/etc/systemd/system/nginx.service.d" +printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" >/etc/systemd/system/nginx.service.d/override.conf +systemctl daemon-reload >/dev/null +systemctl enable nginx >/dev/null 2>&1 + +[[ ! -f "/var/www/ssl/dhparam.pem" ]] && openssl dhparam -out /var/www/ssl/dhparam.pem 2048 +} + + + +nginxSet(){ +if [[ ! -f "/var/www/ssl/de_GWD.cer" ]] || [[ ! -f "/var/www/ssl/de_GWD.key" ]]; then +cd /var/www/ssl +openssl req -x509 -nodes -days 3650 \ + -subj "/C=CA/ST=QC/O=Company, Inc./CN=localhost.com" \ + -config <(cat /etc/ssl/openssl.cnf \ + <(printf '[SAN]\nsubjectAltName=DNS:localhost')) \ + -newkey rsa:2048 \ + -keyout de_GWD.key \ + -out de_GWD.cer +cd ~ +fi + +[[ -z $serverName ]] && serverName="de_GWD" + +[[ -z $(echo $webUIport | grep '^[[:digit:]]*$') ]] && webUIport="443" +jq --arg webUIport $webUIport '.address.webUIport=$webUIport' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +if [[ $webUIport = 443 ]]; then +cat << EOF >/etc/nginx/conf.d/80.conf +server { + listen 80 reuseport; + server_name $serverName; + return 301 https://\$host\$request_uri; +} +EOF +else +rm -rf /etc/nginx/conf.d/80.conf +fi + +touch /etc/nginx/conf.d/default.conf +sed -i '/SERVER_BASE_START/,/SERVER_BASE_END/d' /etc/nginx/conf.d/default.conf +sed -i '/PHP_START/,/PHP_END/d' /etc/nginx/conf.d/default.conf +sed -i '/TTYD_START/,/TTYD_END/d' /etc/nginx/conf.d/default.conf +sed -i '/NETDATA_START/,/NETDATA_END/d' /etc/nginx/conf.d/default.conf +sed -i '$s/}$//' /etc/nginx/conf.d/default.conf + +until [[ $(head -1 /etc/nginx/conf.d/default.conf | cat -e) != "$" ]]; do + sed -i '1d' /etc/nginx/conf.d/default.conf +done + +until [[ $(tail -1 /etc/nginx/conf.d/default.conf | cat -e) != "$" ]]; do + sed -i '$d' /etc/nginx/conf.d/default.conf +done + +cat << EOF >/etc/nginx/conf.d/.HSTS +add_header X-Download-Options "noopen" always; +add_header X-Permitted-Cross-Domain-Policies "none" always; +add_header X-Robots-Tag "none" always; + +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; +add_header X-XSS-Protection "1; mode=block" always; +add_header X-Frame-Options "SAMEORIGIN" always; +add_header X-Content-Type-Options "nosniff" always; +EOF + +cat << EOF >/etc/nginx/conf.d/.ssl_certs +ssl_certificate /var/www/ssl/de_GWD.cer; +ssl_certificate_key /var/www/ssl/de_GWD.key; +ssl_dhparam /var/www/ssl/dhparam.pem; +ssl_protocols TLSv1.3; +ssl_ecdh_curve CECPQ2:X25519:P-256; +ssl_prefer_server_ciphers off; +ssl_ciphers [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; +ssl_session_tickets off; +ssl_session_cache shared:SSL:10m; +ssl_session_timeout 6h; +ssl_buffer_size 4k; +EOF + +if [[ -f "/var/www/ssl/ocsp.resp" ]] && [[ -f "/var/www/ssl/bundle.pem" ]]; then +cat << EOF >>/etc/nginx/conf.d/.ssl_certs +ssl_stapling on; +ssl_stapling_verify on; +ssl_stapling_file /var/www/ssl/ocsp.resp; +ssl_trusted_certificate /var/www/ssl/bundle.pem; +ssl_early_data on; +proxy_set_header Early-Data \$ssl_early_data; +EOF +fi + +cat << EOF >/etc/nginx/conf.d/default.conf +# SERVER_BASE_START +server { + listen $webUIport default ssl http2 fastopen=500 reuseport; + server_name $serverName; + root /var/www/html; + index index.php index.html index.htm; + error_page 497 https://\$host:$webUIport\$request_uri; + + include /etc/nginx/conf.d/.HSTS; + + add_header Referrer-Policy "origin" always; + add_header Pragma "no-cache" always; + + include /etc/nginx/conf.d/.ssl_certs; + +# SERVER_BASE_END + +# PHP_START +location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_pass unix:/run/php/php7.4-fpm.sock; + fastcgi_index index.php; +} +# PHP_END + +# TTYD_START +location ~ ^/ttyd(.*)$ { + proxy_pass http://127.0.0.1:3000/\$1; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Host \$host; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; +} +# TTYD_END + +$(cat /etc/nginx/conf.d/default.conf 2>/dev/null) +} +EOF +systemctl restart nginx +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Nginx${cRES}" +} + + + +installWebUI(){ +rm -rf /tmp/ui-script +rm -rf /tmp/ui-web +unzip /opt/de_GWD/.repo/client.zip -d /tmp >/dev/null 2>&1 + +rm -rf /opt/de_GWD/ui-* +rm -rf /opt/de_GWD/ui_* +rm -rf /var/www/html/*.php +rm -rf /var/www/html/*.ico +rm -rf /var/www/html/act +rm -rf /var/www/html/vendor +rm -rf /var/www/html/css +rm -rf /var/www/html/js + +mv -f /tmp/ui-script/* /opt/de_GWD >/dev/null +mv -f /tmp/ui-web/* /var/www/html >/dev/null + +mkdir -p /var/www/html/restore +chown -R www-data:www-data /var/www/html +chmod -R +x /var/www/html +chmod +x /opt/de_GWD/* + +if [[ $TTYD_UPDATE = "true" ]]; then +[[ -z $(echo $updatePort | grep '^[[:digit:]]*$') ]] && updatePort="3000" + +rm -rf /lib/systemd/system/updateGWD.service +cat << EOF >/etc/systemd/system/updateGWD.service +[Unit] +Description=updateGWD +After=network.target + +[Service] +User=root +Type=oneshot +ExecStartPre=/usr/bin/chmod +x /opt/de_GWD/update +ExecStart=/usr/bin/tmux new -ds 'updateGWD' /usr/bin/ttyd -p $updatePort -o /opt/de_GWD/update +KillMode=process + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +fi + +if [[ $(du -sk /var/www/html/spt 2>/dev/null | awk '{print$1}') -lt 102400 ]]; then + dd if=/dev/zero of=/var/www/html/spt bs=1k count=100k status=progress +fi + +cp -f /opt/de_GWD/.repo/version.php /var/www/html/act/version.php +} + + + +piholeConf(){ +rm -rf /etc/pihole/setupVars* +cat << EOF >/etc/pihole/setupVars.conf +PIHOLE_INTERFACE=$ethernetnum +IPV4_ADDRESS=$localAddrCIDR +WEBPASSWORD=$piholePW +API_EXCLUDE_DOMAINS=www.google.com,www.baidu.com,raw.githubusercontent.com,api.cloudflare.com,myip.ipip.net,v4.yinghualuo.cn,www.f3322.org,*.in-addr.arpa,*._udp.lan +INSTALL_WEB_SERVER=true +INSTALL_WEB_INTERFACE=true +LIGHTTPD_ENABLED=false +CACHE_SIZE=10000 +QUERY_LOGGING=true +BLOCKING_ENABLED=true +DNS_FQDN_REQUIRED=true +DNS_BOGUS_PRIV=true +DNSMASQ_LISTENING=all +DNSSEC=false +REV_SERVER=false +PIHOLE_DNS_1=127.0.0.1#5341 +EOF +} + + + +installPihole(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Install Pi-hole${cRES}\r\c" +piholeCoreVer=$(pihole -v 2>/dev/null | awk -F'is ' '{print$2}' | awk 'NR==1{print$1}') +piholeWebUIVer=$(pihole -v 2>/dev/null | awk -F'is ' '{print$2}' | awk 'NR==2{print$1}') +piholeFTLVer=$(pihole -v 2>/dev/null | awk -F'is ' '{print$2}' | awk 'NR==3{print$1}') + +piholeCoreRelease=$(curl -sSLI "https://github.com/pi-hole/pi-hole/releases/latest" | grep "location:" | awk -F'/' '{print$NF}' | tr -cd "[:print:]\n") +piholeWebUIRelease=$(curl -sSLI "https://github.com/pi-hole/AdminLTE/releases/latest" | grep "location:" | awk -F'/' '{print$NF}' | tr -cd "[:print:]\n") +piholeFTLRelease=$(curl -sSLI "https://github.com/pi-hole/FTL/releases/latest" | grep "location:" | awk -F'/' '{print$NF}' | tr -cd "[:print:]\n") + +[[ -z $piholePW ]] && piholePW="0000000000000000000000000000000000000000000000000000000000000000" + +[[ $piholeCoreVer = $piholeCoreRelease ]] && [[ $piholeFTLVer = $piholeFTLRelease ]] && [[ $piholeWebUIVer = $piholeWebUIRelease ]] && return + +[[ -n "$(ps -e | grep 'pihole-FTL' )" ]] && systemctl stop pihole-FTL +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 +rm -rf /etc/.pihole /etc/pihole /opt/pihole /usr/bin/pihole-FTL /usr/local/bin/pihole /var/www/html/pihole /var/www/html/admin /var/log/pihole* /etc/dnsmasq.d/* +systemctl unmask lighttpd >/dev/null 2>&1 +systemctl unmask dhcpcd >/dev/null 2>&1 + +mkdir -p /etc/.pihole +mkdir -p /etc/pihole +cat << EOF >/etc/pihole/adlists.list +https://raw.githubusercontent.com/kboghdady/youTube_ads_4_pi-hole/master/youtubelist.txt +EOF + +piholeConf + +git clone https://github.com/pi-hole/pi-hole /etc/.pihole +cat "/etc/.pihole/automated install/basic-install.sh" | PIHOLE_SKIP_OS_CHECK=true bash /dev/stdin --unattended +chmod -R 755 /var/www/html +usermod -aG pihole www-data + +PIHOLE_UPDATE="true" +} + + + +piholeSet(){ +systemctl disable --now lighttpd >/dev/null 2>&1 +systemctl disable --now dhcpcd >/dev/null 2>&1 +systemctl mask --now lighttpd >/dev/null 2>&1 +systemctl mask --now dhcpcd >/dev/null 2>&1 +systemctl daemon-reload >/dev/null + +rm -rf /var/www/html/index.lighttpd.orig +update-rc.d -f dhcpd remove >/dev/null 2>&1 + +cat << EOF >/etc/hosts +127.0.0.1 localhost +$localAddr $(hostname).local $(hostname) + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +EOF + +piholeConf + +>/etc/pihole/dns-servers.conf +cat << EOF >/etc/pihole/pihole-FTL.conf +BLOCKINGMODE=NULL +CNAME_DEEP_INSPECT=true +BLOCK_ESNI=true +EDNS0_ECS=false +RATE_LIMIT=0/0 +REPLY_WHEN_BUSY=ALLOW +MOZILLA_CANARY=true +BLOCK_ICLOUD_PR=false + +MAXLOGAGE=24.0 +PRIVACYLEVEL=0 +IGNORE_LOCALHOST=no +AAAA_QUERY_ANALYSIS=no +SHOW_DNSSEC=false + +SOCKET_LISTENING=localonly +FTLPORT=4711 +RESOLVE_IPV6=no +RESOLVE_IPV4=yes +PIHOLE_PTR=PI.HOLE +DELAY_STARTUP=0 +NICE=-10 +MAXNETAGE=3 +NAMES_FROM_NETDB=true +REFRESH_HOSTNAMES=IPV4 +PARSE_ARP_CACHE=true +CHECK_LOAD=false + +DBIMPORT=yes +MAXDBDAYS=3 +DBINTERVAL=10.0 +EOF + +cat << EOF >/etc/dnsmasq.d/00-extra.conf +dns-forward-max=10000 +edns-packet-max=1280 +all-servers +EOF + +cat << "EOF" >/opt/de_GWD/pihole_hotfix +#!/bin/bash +localIP=$(jq -r '.address.localIP' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +sed -i "/dhcp-option=/c\dhcp-option=6,$localIP,$localIP" /etc/dnsmasq.d/02-pihole-dhcp.conf +systemctl restart pihole-FTL +EOF +chmod +x /opt/de_GWD/pihole_hotfix + +sed -i '/pihole_hotfix/d' /var/www/html/admin/scripts/pi-hole/php/savesettings.php +sed -i "/sudo pihole -a enabledhcp/a\exec('sudo /opt/de_GWD/pihole_hotfix >/dev/null 2>&1');" /var/www/html/admin/scripts/pi-hole/php/savesettings.php + +[[ $PIHOLE_UPDATE = "true" ]] && /opt/de_GWD/ui-submitADList + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Pi-hole Config ${cRES}" +} + + + +postInstall(){ +/opt/de_GWD/ui-NodeOne +/opt/de_GWD/ui_4am +/opt/de_GWD/ui_4h + +if [[ $(jq -r '.FORWARD.block53' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-block53on +fi + +echo + +sed -i '/interface=/d' /etc/dnsmasq.d/01-pihole.conf +sed -i '/server=/d' /etc/dnsmasq.d/01-pihole.conf +awk '/PIHOLE_DNS_/' /etc/pihole/setupVars.conf | cut -d = -f 2 | sed 's/^/server=/g' >>/etc/dnsmasq.d/01-pihole.conf + +rm -rf /etc/dnsmasq.conf* +cat << EOF >/etc/dnsmasq.conf +conf-dir=/etc/dnsmasq.d +listen-address=127.0.0.1 +port=53 +EOF + +if [[ $(jq -r '.address.dhcp' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-DHCPon +else + /opt/de_GWD/ui-DHCPoff +fi + +if [[ -n $(jq -r '.address.alias' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then + /opt/de_GWD/ui-markThis >/dev/null 2>&1 +fi + +if [[ $(jq -r '.v2nodeDIV.nodeSM.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeSM >/dev/null 2>&1 +fi + +if [[ $(jq -r '.v2nodeDIV.nodeCU.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeCU >/dev/null 2>&1 +fi + +if [[ $(jq -r '.v2nodeDIV.nodeDT.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeDT >/dev/null 2>&1 +fi + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}V2 Split${cRES}" + +if [[ $(jq -r '.FORWARD.FWD1.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-FWD1save >/dev/null 2>&1 +fi + +if [[ $(jq -r '.FORWARD.Rproxy.client.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-RproxyCsave >/dev/null 2>&1 +fi + +if [[ $(jq -r '.FORWARD.Rproxy.server.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-RproxySsave >/dev/null 2>&1 +fi + +systemctl restart mosdns +systemctl restart vtrui + +/opt/de_GWD/ui_2h + + +cat << EOF >/etc/rc_online.local +#!/bin/bash +echo madvise >/sys/kernel/mm/transparent_hugepage/enabled + +$(which ip) route show table local | grep ' dev lo ' | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 9088 initcwnd 1000 initrwnd 1000 fastopen_no_cookie 1 congctl lock cubic +done + +NIC_local=\$($(which ip) route | grep -v 'scope link' | awk -F' dev ' '{print\$2}' | cut -d' ' -f1) +$(which ip) route show table local | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + +$(which ip) route | grep " dev \$NIC_local " | while read line; do +line=\$(echo \$line | awk -F' mtu ' '{print\$1}') +$(which ip) route change \$line mtu 1500 advmss 1440 initcwnd 32 initrwnd 39 fastopen_no_cookie 1 congctl lock $(sysctl net.ipv4.tcp_congestion_control | awk -F' = ' '{print$2}') +done + + + +NIC_device=\$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device') +for ifb in \$(echo \$NIC_device | xargs -n 1 | grep 'virtual' | awk -F'/' '{print\$NF}' | grep '^ifb'); do +$(which ip) link set \$ifb down +$(which ip) link delete \$ifb +done + +$(which ip) link set lo qlen 4096 mtu 9088 +$(which tc) qdisc del dev lo root >/dev/null 2>&1 +$(which tc) qdisc add dev lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw egress + +$(which ip) link add name ifb4lo type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev lo ingress >/dev/null 2>&1 +$(which tc) qdisc add dev lo handle ffff: ingress +$(which tc) qdisc del dev ifb4lo root >/dev/null 2>&1 +$(which tc) qdisc add dev ifb4lo root cake unlimited rtt 1us diffserv4 triple-isolate nonat nowash no-split-gso no-ack-filter raw ingress +$(which ip) link set ifb4lo qlen 4096 mtu 9088 +$(which ip) link set ifb4lo up +$(which tc) filter add dev lo parent ffff: matchall action mirred egress redirect dev ifb4lo + +echo \$NIC_device | xargs -n 1 | grep 'virtual' | grep -v 'ifb' | awk -F'/' '{print\$NF}' | grep -v '^lo\$' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited metro diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter raw overhead 18 mpu 64 ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth +done + +echo \$NIC_device | xargs -n 1 | grep -v 'virtual' | awk -F'/' '{print\$NF}' | while read line; do +MTU_NUM=\$(< /sys/class/net/\$line/mtu) +ifb4eth=\$(echo "ifb4\$line" | cut -c 1-15) +$(which ip) link set \$line qlen 4096 mtu \$MTU_NUM +$(which tc) qdisc del dev \$line root >/dev/null 2>&1 +$(which tc) qdisc add dev \$line root cake unlimited metro diffserv4 dual-srchost nonat nowash no-split-gso ack-filter-aggressive ethernet egress + +$(which ip) link add name \$ifb4eth type ifb >/dev/null 2>&1 +$(which tc) qdisc del dev \$line ingress >/dev/null 2>&1 +$(which tc) qdisc add dev \$line handle ffff: ingress +$(which tc) qdisc del dev \$ifb4eth root >/dev/null 2>&1 +$(which tc) qdisc add dev \$ifb4eth root cake unlimited regional diffserv4 dual-dsthost nonat nowash no-split-gso ack-filter-aggressive ethernet ingress +$(which ip) link set \$ifb4eth qlen 4096 mtu \$MTU_NUM +$(which ip) link set \$ifb4eth up +$(which tc) filter add dev \$line parent ffff: matchall action mirred egress redirect dev \$ifb4eth + +$(which ethtool) -s \$line duplex full >/dev/null 2>&1 +$(which ethtool) -K \$line rx on tx on sg off tso off gso off gro off lro off >/dev/null 2>&1 +done + +$(which ip) tcp_metrics flush +$(which ip) route flush cache + +systemctl restart nftables + +find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device' | awk -F'/' '{print\$NF}' | xargs -I {} echo "interface={}" >>/etc/dnsmasq.d/00-interface +systemctl restart pihole-FTL +EOF +chmod +x /etc/rc_online.local +/etc/rc_online.local + + +cat << "EOF" >/etc/rc_kernel.local +#!/bin/bash +PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' + +sed -i "/net.core.default_qdisc/d" /etc/sysctl.conf +sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf + +echo "net.core.default_qdisc = cake" >>/etc/sysctl.conf + +if [[ $(uname -r) =~ "bbrplus" ]]; then + echo "net.ipv4.tcp_congestion_control = bbrplus" >>/etc/sysctl.conf +else + echo "net.ipv4.tcp_congestion_control = bbr" >>/etc/sysctl.conf +fi +sysctl -p >/dev/null 2>&1 + +rm -f /var/cache/apt/archives/lock +rm -f /var/lib/apt/lists/lock +rm -f /var/lib/dpkg/lock +rm -f /var/lib/dpkg/lock-frontend +dpkg --configure -a + +dpkg --list | grep linux-image | awk '{print $2}' | grep -Fv $(uname -r) | while read line; do +apt autoremove --purge -y $line +done + +dpkg --list | grep linux-headers | awk '{print $2}' | grep -Fv $(uname -r) | while read line; do +apt autoremove --purge -y $line +done +EOF +chmod +x /etc/rc_kernel.local + + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/\/opt\/de_GWD\/ui_4am/d' /tmp/now.cron +sed -i '/\/opt\/de_GWD\/ui_4h/d' /tmp/now.cron +sed -i '/\/opt\/de_GWD\/ui_2h/d' /tmp/now.cron +sed -i '/\/opt\/de_GWD\/clearKernel/d' /tmp/now.cron +sed -i '/\/etc\/rc_.*/d' /tmp/now.cron +cat << EOF >>/tmp/now.cron +0 4 * * * /opt/de_GWD/ui_4am u +0 */4 * * * /opt/de_GWD/ui_4h +0 */2 * * * /opt/de_GWD/ui_2h +@reboot sleep 10 && /etc/rc_kernel.local +@reboot sleep 30 && /etc/rc_online.local +EOF +crontab /tmp/now.cron +rm -rf /tmp/now.cron +service cron restart + +rm -rf /tmp/ui-script +rm -rf /tmp/ui-web +rm -rf /tmp/client.zip +rm -rf /opt/de_GWD/update + +if [[ $(dpkg --list | grep linux-image | wc -l) != "1" ]]; then +echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]\c" && echo -e "\t${YELLOW}Kernel updated${cRES}" +fi +} + + + +install3rdKernel(){ +bash <(wget --show-progress -cqO- https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/kernel/install3rdKernel) +} + +restoreKernel(){ +bash <(wget --show-progress -cqO- https://raw.githubusercontent.com/jacyl4/de_GWD/main/resource/kernel/installDefaultKernel) +} + + + +changeWP(){ + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} Web UI Port${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read webUIport + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} Web update Port${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read updatePort + +serverName=$(jq -r '.address.serverName' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +nginxSet +systemctl force-reload nginx >/dev/null + +sed -i "/ExecStart=/c\ExecStart=/usr/bin/ttyd -p $updatePort -o /opt/de_GWD/update" /etc/systemd/system/updateGWD.service +systemctl daemon-reload >/dev/null + +jq --arg updatePort $updatePort '.update.updatePort=$updatePort' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Web UI Port & Web update Port ${GREEN}Updated${cRES}" +} + + + +changePWD(){ +sudo pihole -a -p + +piholePW=$(awk '/WEBPASSWORD/' /etc/pihole/setupVars.conf 2>/dev/null | cut -d= -f2) + +jq --arg piholePW "$piholePW" '.address.PWD = $piholePW' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Password ${GREEN}Changed${cRES}" +} + + + +installGWD(){ + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} de_GWD local IP address${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read localAddr + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} Upstream route IP address${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read gatewayAddr + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} DoH / DoG${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read DoGorDOH + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} V2 Address${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read v2addr + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} V2 UUID${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read uuid + + echo -e "${GREEN}=========================== ${cRES}" + echo -e "${GREEN} V2 Path${cRES}" + echo -e "${GREEN}=========================== ${cRES}" + read path + +ethernetnum=$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device' | xargs -n 1 | grep -v 'virtual' | grep -v 'ifb' | awk -F'/' '{print$NF}' | head -n1) +netmask=$(ip route | grep "$ethernetnum" | awk 'NR==2{print$1}' | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g') +localAddr=$(echo $localAddr | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +localAddrCIDR=$(echo "$localAddr$netmask") +localCIDR="$(echo $localAddr | cut -d . -f1-3).0$netmask" + +if [[ $DoGorDOH =~ "/" ]]; then +doh1=$DoGorDOH +else +DoG=$DoGorDOH +fi + +domain=$(echo $v2addr | cut -d: -f1) +port=$(echo $v2addr | cut -d: -f2 | grep '^[[:digit:]]*$') +[[ -z $port ]] && port="443" +tls=$domain + +rm -rf /etc/resolv.conf +cat << EOF >/etc/resolv.conf +nameserver 119.29.29.29 +nameserver 180.76.76.76 +nameserver 114.114.114.114 +nameserver 223.5.5.5 +EOF + +if [[ $(cat /etc/os-release | grep VERSION= | cut -d'(' -f2 | cut -d')' -f1) = "stretch" ]]; then +cat << EOF >/etc/apt/sources.list +deb http://$chnAPTsource/debian buster main contrib non-free +deb http://$chnAPTsource/debian buster-updates main contrib non-free +deb http://$chnAPTsource/debian-security buster/updates main contrib non-free +EOF + +sed -i "s/ stretch / buster /g" /etc/apt/sources.list.d/* >/dev/null 2>&1 +apt update --fix-missing && apt upgrade --allow-downgrades -y +apt full-upgrade -y && apt autoremove --purge -y && apt clean -y && apt autoclean -y +fi + +cat << EOF >/etc/apt/sources.list +deb http://$chnAPTsource/debian bookworm main contrib non-free non-free-firmware +deb http://$chnAPTsource/debian bookworm-updates main contrib non-free non-free-firmware +deb http://$chnAPTsource/debian bookworm-backports main contrib non-free non-free-firmware +deb http://$chnAPTsource/debian-security bookworm-security main contrib non-free non-free-firmware +EOF + +sed -i "s/ buster / bookworm /g" /etc/apt/sources.list.d/* >/dev/null 2>&1 +sed -i "s/ bullseye / bookworm /g" /etc/apt/sources.list.d/* >/dev/null 2>&1 +apt update --fix-missing && apt upgrade --allow-downgrades -y +apt full-upgrade -y && apt autoremove --purge -y && apt clean -y && apt autoclean -y + +preInstall + +preConf + +preDL + +installSmartDNS + +installXray + +installNftables + +echo "{}" >/opt/de_GWD/0conf +jq '.address={}' /opt/de_GWD/0conf |\ +jq '.dns={}' |\ +jq '.v2node=[]' |\ +jq '.update={}' |\ +jq --arg localIP "$localAddrCIDR" '.address.localIP=$localIP' |\ +jq --arg upstreamIP "$gatewayAddr" '.address.upstreamIP=$upstreamIP' |\ +jq --arg domain "$v2addr" '.v2node[0].domain=$domain' |\ +jq --arg name "$v2addr" '.v2node[0].name=$name' |\ +jq --arg uuid "$uuid" '.v2node[0].uuid=$uuid' |\ +jq --arg path "$path" '.v2node[0].path=$path' |\ +jq --arg updateAddr "$localAddr" '.update.updateAddr=$updateAddr' |\ +jq --arg updatePort "3000" '.update.updatePort=$updatePort' |\ +jq --arg updateCMD "$installCMD" '.update.updateCMD=$updateCMD' |\ +jq --arg domain "$domain" '.update.v2node.domain=$domain' |\ +jq --arg port "$port" '.update.v2node.port=$port' |\ +jq --arg tls "$tls" '.update.v2node.tls=$tls' |\ +jq --arg uuid "$uuid" '.update.v2node.uuid=$uuid' |\ +jq --arg path "$path" '.update.v2node.path=$path' | sponge /opt/de_GWD/0conf +[[ -n $DoG ]] && jq --arg DoG "$DoG" '.dns.DoG=$DoG' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +[[ -n $doh1 ]] && jq --arg doh1 "$doh1" '.dns.doh+=[$doh1]' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +de_GWDconnect + +updateAPT + +apt --reinstall install ca-certificates + +installDep + +repoDL + +installNginx + +nginxSet + +installWebUI + +installPihole + +piholeSet + +postInstall + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}de_GWD ${GREEN}Installed${cRES}" +} + + + +updateGWD(){ +[[ -f "/opt/de_GWD/version.php" ]] && echo -e "${RED}This is not client${cRES}" && exit + +cleanDep + +preUpdate + +if [[ $1 = "auto" ]]; then +de_GWDconnect u a +else +de_GWDconnect u +fi + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}de_GWD ${GREEN}Updated${cRES}" +} + + + +updateGWD_Green(){ +repoDL + +installDep + +installNginx + +nginxSet + +installWebUI + +preInstall + +preConf + +installSmartDNS + +installXray + +installNftables + +installPihole + +piholeSet + +postInstall +} + +updateGWD_Red(){ +preInstall + +preConf + +preDL + +installSmartDNS + +installXray + +installNftables + +de_GWDconnect + +installDep + +repoDL + +installNginx + +nginxSet + +installWebUI + +installPihole + +piholeSet + +postInstall +} + + + +start_menu(){ +echo +if [[ $(systemctl is-active 'smartdns') = "active" ]]; then + echo -e "${WHITE} SmartDNS \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [[ ! -x "/opt/de_GWD/smartdns/smartdns" ]]; then + echo -e "${WHITE} SmartDNS \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} SmartDNS \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(systemctl is-active 'mosdns') = "active" ]]; then + echo -e "${WHITE} mosdns \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [[ ! -x "/opt/de_GWD/mosdns/mosdns" ]]; then + echo -e "${WHITE} mosdns \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} mosdns \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(systemctl is-active 'pihole-FTL') = "active" ]]; then + echo -e "${WHITE} Pi-hole \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [[ ! -x "/usr/local/bin/pihole" ]]; then + echo -e "${WHITE} Pi-hole \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} Pi-hole \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(systemctl is-active 'vtrui') = "active" ]]; then + echo -e "${WHITE} Xray \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [[ ! -x "/opt/de_GWD/vtrui/vtrui" ]]; then + echo -e "${WHITE} Xray \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} Xray \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(systemctl is-active 'nginx') = "active" ]]; then + echo -e "${WHITE} Nginx \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [[ ! -x "/usr/sbin/nginx" ]]; then + echo -e "${WHITE} Nginx \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} Nginx \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(systemctl is-active 'php7.4-fpm') = "active" ]]; then + echo -e "${WHITE} php7.4-FPM \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +elif [ ! -f "/etc/php/7.4/fpm/php-fpm.conf" ]; then + echo -e "${WHITE} php7.4-FPM \c" && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]${cRES}" +else + echo -e "${WHITE} php7.4-FPM \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ -n $(crontab -l 2>&1 | grep "autoUpdate") ]] && [[ -f "/opt/de_GWD/autoUpdate" ]]; then + echo -e "${WHITE} AutoUpdate \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +else + echo -e "${WHITE} AutoUpdate \c" && echo -e "${WHITE}[ ${WHITE}- ${WHITE}]${cRES}" +fi + +echo -e "${WHITE}---------------------- ${cRES}" + +if [[ $(du -sk /opt/de_GWD/.repo/geosite.dat 2>/dev/null | awk '{print$1}') -gt 3500 ]]; then + echo -e "${WHITE} GeoSite \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +else + echo -e "${WHITE} GeoSite \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(du -sk /opt/de_GWD/.repo/geoip.dat 2>/dev/null | awk '{print$1}') -ge 8000 ]]; then + echo -e "${WHITE} GeoIP \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +else + echo -e "${WHITE} GeoIP \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + +if [[ $(du -sk /opt/de_GWD/nftables/IP_CHNROUTE 2>/dev/null | awk '{print$1}') -gt 100 ]]; then + echo -e "${WHITE} ChnrouteIP \c" && echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]${cRES}" +else + echo -e "${WHITE} ChnrouteIP \c" && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]${cRES}" +fi + echo + echo -e "${BLUE}---------------------------------------------------------------- ${cRES}" + echo -e "${BLUE}Debian Version: $(cat /etc/os-release | grep VERSION= | cut -d'(' -f2 | cut -d')' -f1) ${cRES}" + echo -e "${BLUE}Kernel: $(uname -r) ${cRES}" + echo -e "${BLUE}---------------------------------------------------------------- ${cRES}" + + echo -e "${GREEN}============CLIENT============================================== ${cRES}" + echo -e "${GREEN} __ _______ ______ ${cRES}" + echo -e "${GREEN} ____/ /__ / ____/ | / / __ \ ${cRES}" + echo -e "${GREEN} / __ / _ \ / / __ | | /| / / / / / ${cRES}" + echo -e "${GREEN}/ /_/ / __/ / /_/ / | |/ |/ / /_/ / ${cRES}" + echo -e "${GREEN}\__,_/\___/____\____/ |__/|__/_____/ ${cRES}" + echo -e "${GREEN} /_____/ ${cRES}" + echo + echo -e "${GREEN}Require: Debian (amd64 && arm64) ${cRES}" + echo -e "${GREEN}Author: JacyL4${cRES}" + echo -e "${GREEN}================================================================ ${cRES}" + echo + echo -e "${GREEN}1. Install de_GWD${cRES}" + echo -e "${GREEN}2. Install BBRplus / Liquorix / XanMod kernel and reboot${cRES}" + echo -e "${BLUE}3. Restore default kernel and reboot${cRES}" +echo -e "${YELLOW}8. Change Web UI port & Web update port${cRES}" +echo -e "${YELLOW}9. Change de_GWD password${cRES}" +echo -e "${YELLOW}0. Update de_GWD${cRES}" +echo -e "${RED}CTRL+C EXIT${cRES}" +echo "" +read -p "Select:" num + case "$num" in + 1) + installGWD + start_menu + ;; + 2) + install3rdKernel + start_menu + ;; + 3) + restoreKernel + start_menu + ;; + 8) + changeWP + start_menu + ;; + 9) + changePWD + start_menu + ;; + 0) + updateGWD + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/de_GWD_amd64.zip b/de_GWD_amd64.zip new file mode 100755 index 000000000..218abbe7c Binary files /dev/null and b/de_GWD_amd64.zip differ diff --git a/de_GWD_amd64.zip.sha256sum b/de_GWD_amd64.zip.sha256sum new file mode 100644 index 000000000..611fc9250 --- /dev/null +++ b/de_GWD_amd64.zip.sha256sum @@ -0,0 +1 @@ +54e0edc5678b8d3711a93bd7c57fde3173c686ad48e1095f17417ed7b7112305 diff --git a/de_GWD_arm64.zip b/de_GWD_arm64.zip new file mode 100755 index 000000000..ccfa9b1e4 Binary files /dev/null and b/de_GWD_arm64.zip differ diff --git a/de_GWD_arm64.zip.sha256sum b/de_GWD_arm64.zip.sha256sum new file mode 100644 index 000000000..6ae1c1fd6 --- /dev/null +++ b/de_GWD_arm64.zip.sha256sum @@ -0,0 +1 @@ +4a9612aa12a70538ac8346f84326805e8a5d8aae602b203fa53fe5f072f00841 diff --git a/resource/client/Archive.zip b/resource/client/Archive.zip new file mode 100644 index 000000000..2c375df13 Binary files /dev/null and b/resource/client/Archive.zip differ diff --git a/resource/client/Archive.zip.sha256sum b/resource/client/Archive.zip.sha256sum new file mode 100755 index 000000000..c5ccc7930 --- /dev/null +++ b/resource/client/Archive.zip.sha256sum @@ -0,0 +1 @@ +fea0459ca7c2dfb33a2d9fe33df979e7c1903e1ee34f7c323aeea657506d10f9 diff --git a/resource/client/ui-script/ui-DHCPoff b/resource/client/ui-script/ui-DHCPoff new file mode 100755 index 000000000..caedc54c0 --- /dev/null +++ b/resource/client/ui-script/ui-DHCPoff @@ -0,0 +1,38 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +sed -i '/REV_SERVER=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_CIDR=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_TARGET=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_DOMAIN=/d' /etc/pihole/setupVars.conf +if [[ $(jq -r '.FORWARD.block53' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then +cat << EOF >> /etc/pihole/setupVars.conf +REV_SERVER=false +EOF +else +upstreamIP=$(jq -r '.address.upstreamIP' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +localAddrCIDR=$(jq -r '.address.localIP' /opt/de_GWD/0conf | grep -v '^null$') +localAddr=$(echo $localAddrCIDR | cut -d / -f1) +netmask=$(echo $localAddrCIDR | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g') + +[[ -z $netmask ]] && netmask="/24" && localAddrCIDR="$localAddr$netmask" +cat << EOF >> /etc/pihole/setupVars.conf +REV_SERVER=true +REV_SERVER_CIDR=$localAddrCIDR +REV_SERVER_TARGET=$upstreamIP +EOF +fi + +pihole -a disabledhcp >/dev/null 2>&1 + +jq '.address.dhcp="off"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf diff --git a/resource/client/ui-script/ui-DHCPon b/resource/client/ui-script/ui-DHCPon new file mode 100755 index 000000000..6805f34c0 --- /dev/null +++ b/resource/client/ui-script/ui-DHCPon @@ -0,0 +1,38 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +localAddrCIDR=$(jq -r '.address.localIP' /opt/de_GWD/0conf | grep -v '^null$') +localAddr=$(echo $localAddrCIDR | cut -d / -f1) +netmask=$(echo $localAddrCIDR | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g') + +[[ -z $netmask ]] && netmask="/24" && localAddrCIDR="$localAddr$netmask" +netmaskNUM=$(echo $netmask | cut -d / -f2) + +dhcpStart=$(jq -r '.address.dhcpStart' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +dhcpEnd=$(jq -r '.address.dhcpEnd' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') + +if [[ -n $dhcpStart ]] && [[ -n $dhcpEnd ]] && [[ -n $localAddr ]]; then +sed -i '/REV_SERVER=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_CIDR=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_TARGET=/d' /etc/pihole/setupVars.conf +sed -i '/REV_SERVER_DOMAIN=/d' /etc/pihole/setupVars.conf +cat << EOF >> /etc/pihole/setupVars.conf +REV_SERVER=false +EOF + +sudo pihole -a enabledhcp "$dhcpStart" "$dhcpEnd" "$localAddr" "$netmaskNUM" "local" >/dev/null 2>&1 + +/opt/de_GWD/pihole_hotfix + +jq '.address.dhcp="on"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf +fi diff --git a/resource/client/ui-script/ui-DNSclear b/resource/client/ui-script/ui-DNSclear new file mode 100755 index 000000000..4b03efdf3 --- /dev/null +++ b/resource/client/ui-script/ui-DNSclear @@ -0,0 +1,5 @@ +#!/bin/bash +[[ -n "$(ps -e | grep 'pihole-FTL' )" ]] && systemctl stop pihole-FTL +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 +rm -rf rm /etc/pihole/pihole-FTL.db +systemctl restart pihole-FTL diff --git a/resource/client/ui-script/ui-DNSsplit b/resource/client/ui-script/ui-DNSsplit new file mode 100755 index 000000000..fa8201b7b --- /dev/null +++ b/resource/client/ui-script/ui-DNSsplit @@ -0,0 +1,149 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}DNS Split${cRES}\r\c" +/opt/de_GWD/ui-NodeSave +/opt/de_GWD/ui-submitListBW + +doh1=$(jq -r '.dns.doh[0]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +doh2=$(jq -r '.dns.doh[1]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +dog=$(jq -r '.dns.dog' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +cat << EOF >/opt/de_GWD/mosdns/forwarders.yaml +plugins: + - tag: forward_global + type: forward + args: + concurrent: 1 + upstreams: + - tag: forward_smartdns + addr: 127.0.0.1:5332 +EOF + +cat << EOF >/opt/de_GWD/mosdns/hosts.yaml +plugins: + - tag: hosts + type: hosts + args: + entries: + - localhost 127.0.0.1 +EOF + +if [[ -n $doh1IP ]]; then +doh1Domain=$(echo $doh1 | cut -d/ -f1 | cut -d: -f1) +doh1IP=$(dig @127.0.0.1 $doh1Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +yq eval -i ".plugins.[0].args.entries += [\"$doh1Domain $doh1IP\"]" /opt/de_GWD/mosdns/hosts.yaml +fi + +if [[ -n $doh2IP ]]; then +doh2Domain=$(echo $doh2 | cut -d/ -f1 | cut -d: -f1) +doh2IP=$(dig @127.0.0.1 $doh2Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +yq eval -i ".plugins.[0].args.entries += [\"$doh2Domain $doh2IP\"]" /opt/de_GWD/mosdns/hosts.yaml +fi + +>/etc/dnsmasq.d/98-resolv.conf +>/etc/pihole/custom.list + +if [[ -n $(jq -r '.dns.hosts' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then +jq -r '.dns.hosts | to_entries[] | [.value, .key] | @tsv' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | sed 's/[[:space:]][[:space:]]*/ /g' | while read line; do +if [[ -n $(echo $line | grep "*") ]]; then + hostDomain=$(echo $line | awk '{print$2}' | cut -d'.' -f2-) + hostIP=$(echo $line | awk '{print$1}') + echo "address=/$hostDomain/$hostIP" >>/etc/dnsmasq.d/98-resolv.conf +else + hostDomain=$(echo $line | awk '{print$2}') + hostIP=$(echo $line | awk '{print$1}') + echo "$hostIP $hostDomain" >>/etc/pihole/custom.list + yq eval -i ".plugins.[0].args.entries += [\"$hostDomain $hostIP\"]" /opt/de_GWD/mosdns/hosts.yaml +fi +done +else +>/etc/pihole/custom.list +sed -i '/c/{p;:a;N;$!ba;d}' /opt/de_GWD/mosdns/hosts.yaml +fi + + + +cat << EOF >/opt/de_GWD/mosdns/config.yaml +log: + level: error + +include: + - hosts.yaml + - forwarders.yaml + +plugins: + - tag: chn_sequence + type: sequence + args: + - exec: forward 127.0.0.1:5331 tcp://127.0.0.1:5331 + - matches: resp_ip &/opt/de_GWD/.repo/IPchnroute + exec: accept + - exec: reject + + - tag: global_sequence + type: sequence + args: + - exec: \$forward_global + - exec: accept + + - tag: fallback + type: fallback + args: + primary: chn_sequence + secondary: global_sequence + threshold: 300 + always_standby: true + + - tag: main_sequence + type: sequence + args: + - exec: \$hosts + - matches: has_resp + exec: accept + + - matches: qname &/opt/de_GWD/mosdns/domains_listB + exec: goto global_sequence + + - matches: qname &/opt/de_GWD/mosdns/domains_listW + exec: forward 127.0.0.1:5331 tcp://127.0.0.1:5331 + - matches: has_resp + exec: accept + + - matches: qname &/opt/de_GWD/mosdns/domains_nodes + exec: goto global_sequence + + - matches: qname &/opt/de_GWD/.repo/Domains.chn.txt + exec: \$fallback + + - exec: goto global_sequence + + - type: udp_server + args: + entry: main_sequence + listen: 127.0.0.1:5341 + + - type: tcp_server + args: + entry: main_sequence + listen: 127.0.0.1:5341 +EOF +systemctl restart mosdns + +if [[ $? -ne 0 ]]; then +sed -i '/Nice=/d' /etc/systemd/system/mosdns.service +systemctl daemon-reload >/dev/null +systemctl restart mosdns +fi +systemctl enable mosdns >/dev/null 2>&1 + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}DNS Split${cRES}" diff --git a/resource/client/ui-script/ui-DoGsSave b/resource/client/ui-script/ui-DoGsSave new file mode 100755 index 000000000..bd8c2b352 --- /dev/null +++ b/resource/client/ui-script/ui-DoGsSave @@ -0,0 +1,22 @@ +#!/bin/bash +DoGsPort=$(jq -r '.FORWARD.DoGs.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +if [[ -n $DoGsPort ]]; then +touch /opt/de_GWD/coredns/corefile +sed -i '/DoGs_START/,/DoGs_END/d' /opt/de_GWD/coredns/corefile +tac /opt/de_GWD/coredns/corefile | awk 'NF>0{x=1}x' | tac | sponge /opt/de_GWD/coredns/corefile >/dev/null 2>&1 +cat << EOF >>/opt/de_GWD/coredns/corefile + +# DoGs_START +grpc://.:$DoGsPort { + tls /var/www/ssl/de_GWD.cer /var/www/ssl/de_GWD.key + forward . 127.0.0.1:53 { + prefer_udp + } +} +# DoGs_END +EOF + +systemctl enable coredns >/dev/null 2>&1 +systemctl restart coredns +fi diff --git a/resource/client/ui-script/ui-DoGsStop b/resource/client/ui-script/ui-DoGsStop new file mode 100755 index 000000000..e872fb460 --- /dev/null +++ b/resource/client/ui-script/ui-DoGsStop @@ -0,0 +1,8 @@ +#!/bin/bash +sed -i '/DoGs_START/,/DoGs_END/d' /opt/de_GWD/coredns/corefile +if [[ $(cat /opt/de_GWD/coredns/corefile | wc -c) -lt 11 ]]; then +systemctl disable coredns >/dev/null 2>&1 +systemctl stop coredns +else +systemctl restart coredns +fi diff --git a/resource/client/ui-script/ui-FWD0save b/resource/client/ui-script/ui-FWD0save new file mode 100755 index 000000000..391efa385 --- /dev/null +++ b/resource/client/ui-script/ui-FWD0save @@ -0,0 +1,27 @@ +#!/bin/bash +FWD0port=$(jq -r '.FORWARD.FWD0.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +FWD0uuid=$(jq -r '.FORWARD.FWD0.uuid[].FWD0uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +FWD0in=`cat << EOF + { + "tag": "forward0", + "port": $FWD0port, + "protocol": "vmess", + "settings":{ + "clients":[] + }, + "streamSettings": { + "network": "tcp" + } + } +EOF +` +jq --argjson FWD0in "$FWD0in" '.inbounds[1]=$FWD0in' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + +for uuid in $FWD0uuid; do +uuidStr='{"id":"'$uuid'","alterId":0}' +jq --argjson uuidStr1 "$uuidStr" '.inbounds[1].settings.clients+=[$uuidStr1]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json +done +chmod 644 /var/www/ssl/*.key + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null diff --git a/resource/client/ui-script/ui-FWD0stop b/resource/client/ui-script/ui-FWD0stop new file mode 100755 index 000000000..1ab96514f --- /dev/null +++ b/resource/client/ui-script/ui-FWD0stop @@ -0,0 +1,3 @@ +#!/bin/bash +jq 'del(.inbounds[] | select(.tag == "forward0"))' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json +systemctl restart vtrui >/dev/null diff --git a/resource/client/ui-script/ui-FWD1save b/resource/client/ui-script/ui-FWD1save new file mode 100755 index 000000000..93d7cbae6 --- /dev/null +++ b/resource/client/ui-script/ui-FWD1save @@ -0,0 +1,174 @@ +#!/bin/bash +FWD1port=$(jq -r '.FORWARD.FWD1.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +FWD1uuid=$(jq -r '.FORWARD.FWD1.uuid[].FWD1uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +FWD1upstream=$(jq -r '.FORWARD.FWD1.upstream' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +rm -rf /opt/de_GWD/vtrui1 +mkdir -p /opt/de_GWD/vtrui1 +cp -f /opt/de_GWD/vtrui/vtrui /opt/de_GWD/vtrui1/vtrui1 +chmod +x /opt/de_GWD/vtrui1/vtrui1 + +v2nodeID=$(jq -r --arg FWD1upstream $FWD1upstream '.v2node | to_entries[] | select(.value.domain == $FWD1upstream) | .key' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +address=$(jq -r --arg v2nodeID "$v2nodeID" ".v2node[$v2nodeID].domain" /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +domain=$(echo $address | cut -d: -f1) +port=$(echo $address | cut -d: -f2 | grep '^[[:digit:]]*$') +[[ -z $port ]] && port="443" +[[ -z $tls ]] && tls=$domain + +tls=$(jq -r --arg v2nodeID "$v2nodeID" ".v2node[$v2nodeID].tls" /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +uuid=$(jq -r --arg v2nodeID "$v2nodeID" ".v2node[$v2nodeID].uuid" /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +path=$(jq -r --arg v2nodeID "$v2nodeID" ".v2node[$v2nodeID].path" /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +cat << EOF >/opt/de_GWD/vtrui1/config.json +{ + "log": { + "access":"none", + "error":"none", + "loglevel":"none" + }, + "dns":{ + "tag":"dnsflow", + "queryStrategy":"UseIP", + "disableCache":true, + "servers":["tcp+local://127.0.0.1:53"] + }, + "routing":{ + "rules":[ + ] + }, + "inbounds":[ + { + "port": $FWD1port, + "protocol": "vmess", + "settings":{ + "clients":[] + }, + "streamSettings": { + "network": "tcp" + } + } + ] +} +EOF + +if [[ -z $path ]]; then +OBfwd=`cat << EOF + { + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } + } +EOF +` +else +OBfwd=`cat << EOF +{ + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "path": "$path", + "headers": { + "Host": "$tls" + } + }, + "security": "tls", + "tlsSettings": { + "serverName": "$tls", + "allowInsecure": false + }, + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } +} +EOF +` +fi + +OBdir=`cat << EOF +{ + "tag":"direct", + "protocol":"freedom", + "streamSettings":{"sockopt":{"mark":255}} +} +EOF +` + +for uuid in $FWD1uuid; do +uuidStr='{"id":"'$uuid'","alterId":0}' +jq --argjson uuidStr "$uuidStr" '.inbounds[0].settings.clients+=[$uuidStr]' /opt/de_GWD/vtrui1/config.json | sponge /opt/de_GWD/vtrui1/config.json +done +jq '.outbounds=[]' /opt/de_GWD/vtrui1/config.json |\ +jq --argjson OBfwd "$OBfwd" '.outbounds+=[$OBfwd]' |\ +jq --argjson OBdir "$OBdir" '.outbounds+=[$OBdir]' | sponge /opt/de_GWD/vtrui1/config.json + +chmod 666 /opt/de_GWD/vtrui1/config.json +chmod 644 /var/www/ssl/*.key + +rm -rf /lib/systemd/system/vtrui1.service +cat << "EOF" >/etc/systemd/system/vtrui1.service +[Unit] +Description=vtrui1 +After=network.target nss-lookup.target + +[Service] +User=root +Type=simple +ExecStart=/opt/de_GWD/vtrui1/vtrui1 run -config /opt/de_GWD/vtrui1/config.json +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +Nice=-9 +AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl restart vtrui1 +if [[ $? -ne 0 ]]; then +sed -i '/Nice=/d' /etc/systemd/system/vtrui1.service +systemctl daemon-reload >/dev/null +systemctl restart vtrui1 +fi +systemctl enable vtrui1 >/dev/null 2>&1 diff --git a/resource/client/ui-script/ui-FWD1stop b/resource/client/ui-script/ui-FWD1stop new file mode 100755 index 000000000..dcc3c44ae --- /dev/null +++ b/resource/client/ui-script/ui-FWD1stop @@ -0,0 +1,8 @@ +#!/bin/bash +systemctl stop vtrui1 >/dev/null +systemctl disable vtrui1 >/dev/null +rm -rf /lib/systemd/system/vtrui1.service +rm -rf /etc/systemd/system/vtrui1.service +systemctl daemon-reload >/dev/null + +rm -rf /opt/de_GWD/vtrui1 diff --git a/resource/client/ui-script/ui-NFSoff b/resource/client/ui-script/ui-NFSoff new file mode 100755 index 000000000..a45a9d476 --- /dev/null +++ b/resource/client/ui-script/ui-NFSoff @@ -0,0 +1,9 @@ +#!/bin/bash +NFSpoint=$(echo "$1" | sed 's/\//\\\//g') +sed -i "/$NFSpoint/d" /etc/auto.nfs + +systemctl restart autofs + +awk '{print$1}' /etc/auto.nfs | while read line; do +cd $line +done \ No newline at end of file diff --git a/resource/client/ui-script/ui-NFSon b/resource/client/ui-script/ui-NFSon new file mode 100755 index 000000000..4b40353fe --- /dev/null +++ b/resource/client/ui-script/ui-NFSon @@ -0,0 +1,22 @@ +#!/bin/bash +>/etc/auto.nfs + +nfsNUM=$(jq -r '.app.NFS | length' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +for ((i=0; i<$nfsNUM; i++)); do +NFSpoint=$(jq -r --argjson i "$i" '.app.NFS[$i].NFSpoint' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +NFSserver=$(jq -r --argjson i "$i" '.app.NFS[$i].NFSserver' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +NFSaddress=$(jq -r --argjson i "$i" '.app.NFS[$i].NFSaddress' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +mkdir -p $NFSpoint +echo "$NFSpoint -vers=3,rw,bg,hard,nointr,nolock,timeout=0,rsize=131072,wsize=131072,noatime,nosuid,noresvport $NFSserver:$NFSaddress" >>/etc/auto.nfs +done + +awk '!i[$1]++' /etc/auto.nfs | sponge /etc/auto.nfs + +systemctl enable autofs +systemctl restart autofs + +awk '{print$1}' /etc/auto.nfs | while read line; do +cd $line +done + diff --git a/resource/client/ui-script/ui-NodeCU b/resource/client/ui-script/ui-NodeCU new file mode 100755 index 000000000..a10bbc11d --- /dev/null +++ b/resource/client/ui-script/ui-NodeCU @@ -0,0 +1,38 @@ +#!/bin/bash +tag="custom" + +jq 'del(.outbounds[] | select(.tag == "custom"))' /opt/de_GWD/vtrui/config.json |\ +jq 'del(.routing.rules[] | select(.outboundTag == "custom"))' | sponge /opt/de_GWD/vtrui/config.json + +if [[ -n $2 ]]; then +address=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + +jq --arg address $address '.v2nodeDIV.nodeCU.address=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeCU.address' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +jq -r '.v2nodeDIV.nodeCU.rulesDomain[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' >/tmp/routingDomain +jq -r '.v2nodeDIV.nodeCU.rulesIP[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' >/tmp/routingIP +routingDomain=$(echo $(jq -R -s -c 'split("\n")' < /tmp/routingDomain) | jq -c '.[:-1]') +routingIP=$(echo $(jq -R -s -c 'split("\n")' < /tmp/routingIP) | jq -c '.[:-1]') + +[[ -n $(cat /tmp/routingDomain) ]] && /opt/de_GWD/ui-V2routingDomain $tag $routingDomain +[[ -n $(cat /tmp/routingIP) ]] && /opt/de_GWD/ui-V2routingIP $tag $routingIP + +jq '.v2nodeDIV.nodeCU.status="on"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null +chmod 666 /opt/de_GWD/0conf +rm -rf /tmp/routingDomain +rm -rf /tmp/routingIP diff --git a/resource/client/ui-script/ui-NodeCUcheck b/resource/client/ui-script/ui-NodeCUcheck new file mode 100755 index 000000000..2c2b225f0 --- /dev/null +++ b/resource/client/ui-script/ui-NodeCUcheck @@ -0,0 +1,11 @@ +#!/bin/bash +domain=$(jq -r '.outbounds[] | select(.tag == "custom") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "custom") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck=$domain:$port +fi + +jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf diff --git a/resource/client/ui-script/ui-NodeCUhide b/resource/client/ui-script/ui-NodeCUhide new file mode 100755 index 000000000..707bf84cc --- /dev/null +++ b/resource/client/ui-script/ui-NodeCUhide @@ -0,0 +1,8 @@ +#!/bin/bash +jq 'del(.outbounds[] | select(.tag == "custom"))' /opt/de_GWD/vtrui/config.json |\ +jq 'del(.routing.rules[] | select(.outboundTag == "custom"))' | sponge /opt/de_GWD/vtrui/config.json + +jq '.v2nodeDIV.nodeCU.status="off"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null diff --git a/resource/client/ui-script/ui-NodeChange b/resource/client/ui-script/ui-NodeChange new file mode 100755 index 000000000..6ccc2a895 --- /dev/null +++ b/resource/client/ui-script/ui-NodeChange @@ -0,0 +1,97 @@ +#!/bin/bash +address=$(jq -r --argjson domainNUM "$1" '.v2node | to_entries[] | select(.key == $domainNUM) | .value.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +tls=$(jq -r --argjson domainNUM "$1" '.v2node | to_entries[] | select(.key == $domainNUM) | .value.tls' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +uuid=$(jq -r --argjson domainNUM "$1" '.v2node | to_entries[] | select(.key == $domainNUM) | .value.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +path=$(jq -r --argjson domainNUM "$1" '.v2node | to_entries[] | select(.key == $domainNUM) | .value.path' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +domain=$(echo -e $address | cut -d: -f1) +port=$(echo -e $address | cut -d: -f2 | grep '^[[:digit:]]*$') +[[ -z $port ]] && port="443" +[[ -z $tls ]] && tls=$domain + +jq '.update.v2node={}' /opt/de_GWD/0conf |\ +jq --arg domain "$domain" '.update.v2node.domain=$domain' |\ +jq --arg tls "$tls" '.update.v2node.tls=$tls' |\ +jq --arg port "$port" '.update.v2node.port=$port' |\ +jq --arg uuid "$uuid" '.update.v2node.uuid=$uuid' |\ +jq --arg path "$path" '.update.v2node.path=$path' | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +if [[ -z $path ]]; then +OBdefault=`cat << EOF + { + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + }, + "mux":{"enabled":true,"concurrency":8} + } +EOF +` +else +OBdefault=`cat << EOF + { + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "path": "$path", + "headers": { + "Host": "$tls" + } + }, + "security": "tls", + "tlsSettings": { + "serverName": "$tls", + "allowInsecure": false + }, + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + }, + "mux":{"enabled":true,"concurrency":8} + } +EOF +` +fi + +jq --argjson OBdefault "$OBdefault" '.outbounds[0]=$OBdefault' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + +systemctl restart vtrui diff --git a/resource/client/ui-script/ui-NodeDT b/resource/client/ui-script/ui-NodeDT new file mode 100755 index 000000000..3f2696822 --- /dev/null +++ b/resource/client/ui-script/ui-NodeDT @@ -0,0 +1,81 @@ +#!/bin/bash +tag="divert" + +jq 'del(.outbounds[] | select(.tag == "divert"))' /opt/de_GWD/vtrui/config.json |\ +jq 'del(.routing.rules[] | select(.outboundTag == "divert"))' | sponge /opt/de_GWD/vtrui/config.json + +if [[ -n $2 ]]; then +address=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $2 '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + +jq --arg address $address '.v2nodeDIV.nodeDT.address=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeDT.address' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + else + address=$(jq -r '.update.v2node.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + tls=$(jq -r '.update.v2node.tls' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + port=$(jq -r '.update.v2node.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + uuid=$(jq -r '.update.v2node.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + path=$(jq -r '.update.v2node.path' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +jq -r '.v2nodeDIV.nodeDT.CHNlistProxyIP[]' /opt/de_GWD/0conf 2>/dev/null | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' >/tmp/CHNlistProxyIP +jq -r '.v2nodeDIV.nodeDT.globalProxyIP[]' /opt/de_GWD/0conf 2>/dev/null | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | tee /tmp/globalProxyIP /opt/de_GWD/nftables/IP_listBlan >/dev/null 2>&1 +jq -r '.v2nodeDIV.nodeDT.directProxyIP[]' /opt/de_GWD/0conf 2>/dev/null | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | tee /tmp/directProxyIP /opt/de_GWD/nftables/IP_listWlan >/dev/null 2>&1 +divertIP=$(cat /tmp/CHNlistProxyIP /tmp/globalProxyIP | jq -R -s -c 'split("\n")' | jq -c '.[:-1]') + +[[ -n $(jq '.[]' <<< "$divertIP") ]] && /opt/de_GWD/ui-V2routingSip $tag $divertIP + +jq '.v2nodeDIV.nodeDT.status="on"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_listBlan +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_listBlan +[[ -n $(cat /opt/de_GWD/nftables/IP_listBlan 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listBlan_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listBlan) }" +nft flush set ip de_GWD listBlan +cat << EOF >/opt/de_GWD/nftables/SET_listBlan.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listBlan { + type ipv4_addr + flags interval + auto-merge + $IP_listBlan_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listBlan.nft +/opt/de_GWD/nftables/SET_listBlan.nft + +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_listWlan +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_listWlan +[[ -n $(cat /opt/de_GWD/nftables/IP_listWlan 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listWlan_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listWlan) }" +nft flush set ip de_GWD listWlan +cat << EOF >/opt/de_GWD/nftables/SET_listWlan.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listWlan { + type ipv4_addr + flags interval + auto-merge + $IP_listWlan_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listWlan.nft +/opt/de_GWD/nftables/SET_listWlan.nft + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null +chmod 666 /opt/de_GWD/0conf +rm -rf /tmp/CHNlistProxyIP +rm -rf /tmp/globalProxyIP +rm -rf /tmp/directProxyIP diff --git a/resource/client/ui-script/ui-NodeDTcheck b/resource/client/ui-script/ui-NodeDTcheck new file mode 100755 index 000000000..6f2c3501c --- /dev/null +++ b/resource/client/ui-script/ui-NodeDTcheck @@ -0,0 +1,11 @@ +#!/bin/bash +domain=$(jq -r '.outbounds[] | select(.tag == "divert") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "divert") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck=$domain:$port +fi + +jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf diff --git a/resource/client/ui-script/ui-NodeDThide b/resource/client/ui-script/ui-NodeDThide new file mode 100755 index 000000000..a073792b1 --- /dev/null +++ b/resource/client/ui-script/ui-NodeDThide @@ -0,0 +1,8 @@ +#!/bin/bash +jq 'del(.outbounds[] | select(.tag == "divert"))' /opt/de_GWD/vtrui/config.json |\ +jq 'del(.routing.rules[] | select(.outboundTag == "divert"))' | sponge /opt/de_GWD/vtrui/config.json + +jq '.v2nodeDIV.nodeDT.status="off"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null diff --git a/resource/client/ui-script/ui-NodeOne b/resource/client/ui-script/ui-NodeOne new file mode 100755 index 000000000..554c4fb35 --- /dev/null +++ b/resource/client/ui-script/ui-NodeOne @@ -0,0 +1,78 @@ +#!/bin/bash +tag="default" +domain=$(jq -r '.update.v2node.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +port=$(jq -r '.update.v2node.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +tls=$(jq -r '.update.v2node.tls' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +uuid=$(jq -r '.update.v2node.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +path=$(jq -r '.update.v2node.path' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +address="$domain:$port" + +cat << EOF >/opt/de_GWD/vtrui/config.json +{ +"log": { + "access":"none", + "error":"none", + "loglevel":"none" +}, +"dns":{ + "tag":"dnsflow", + "queryStrategy":"UseIP", + "disableCache":true, + "servers":["tcp+local://127.0.0.1:53"] +}, +"routing":{ + "domainMatcher": "mph", + "domainStrategy": "AsIs", + "rules":[ + { + "type": "field", + "ip": [ + "geoip:private" + ], + "network": "tcp,udp", + "outboundTag": "direct" + } + ] +}, +"inbounds":[ + { + "port":9896, + "listen":"127.0.0.1", + "protocol":"dokodemo-door", + "settings":{"network":"tcp,udp","followRedirect":true}, + "streamSettings":{"sockopt":{"tcpFastOpen":true,"tproxy":"tproxy","mark":255}}, + "sniffing":{"enabled":true,"destOverride":["http","tls","quic"],"routeOnly":true,"metadataOnly":false} + } +] +} +EOF + +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + +OBdirect=`cat << EOF + { + "tag":"direct", + "protocol":"freedom", + "streamSettings":{"sockopt":{"mark":255}} + } +EOF +` +jq --argjson OBdirect "$OBdirect" '.outbounds+=[$OBdirect]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + + + +if [[ $(jq -r '.FORWARD.FWD0.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-FWD0save >/dev/null 2>&1 +fi + + +if [[ $1 = "f" ]]; then + jq '.v2nodeDIV.nodeCU.status="off"' /opt/de_GWD/0conf |\ + jq '.v2nodeDIV.nodeDT.status="off"' | sponge /opt/de_GWD/0conf + chmod 666 /opt/de_GWD/0conf +fi + +if [[ $2 = "r" ]]; then + systemctl restart vtrui +fi diff --git a/resource/client/ui-script/ui-NodeSM b/resource/client/ui-script/ui-NodeSM new file mode 100755 index 000000000..f3937e565 --- /dev/null +++ b/resource/client/ui-script/ui-NodeSM @@ -0,0 +1,231 @@ +#!/bin/bash +jq 'del(.outbounds[] | select(.tag == "nodeSMyoutube"))' /opt/de_GWD/vtrui/config.json |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMnetflix"))' |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMhdh"))' |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMtvb"))' |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMbahamut"))' |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMopenai"))' |\ +jq 'del(.outbounds[] | select(.tag == "nodeSMapple"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMyoutube"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMnetflix"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMhdh"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMtvb"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMbahamut"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMopenai"))' |\ +jq 'del(.routing.rules[] | select(.outboundTag == "nodeSMapple"))' |\ +jq 'del(.routing.rules[] | select(.domain == ["geosite:apple","geosite:apple-ads","geosite:apple-dev","geosite:apple-update","geosite:icloud","geosite:apple@cn","geosite:apple-cn"]))' |\ +jq 'del(.routing.rules[] | select(.domain == ["geosite:category-games@cn"]))' | sponge /opt/de_GWD/vtrui/config.json + + + +if [[ -n $2 ]] && [[ $2 != "0" ]]; then +nodeSMnumYoutube=$[$2-1] +address=$(jq -r --argjson nodecheck $nodeSMnumYoutube '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumYoutube '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumYoutube '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumYoutube '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.youtube=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMyoutube" +routingDomain='["geosite:youtube"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $2 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.youtube)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.youtube' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMyoutube" + routingDomain='["geosite:youtube"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $3 ]] && [[ $3 != "0" ]]; then +nodeSMnumNetflix=$[$3-1] +address=$(jq -r --argjson nodecheck $nodeSMnumNetflix '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumNetflix '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumNetflix '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumNetflix '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.netflix=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMnetflix" +routingDomain='["geosite:netflix"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $3 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.netflix)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.netflix' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMnetflix" + routingDomain='["geosite:netflix"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $4 ]] && [[ $4 != "0" ]]; then +nodeSMnumHDH=$[$4-1] +address=$(jq -r --argjson nodecheck $nodeSMnumHDH '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumHDH '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumHDH '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumHDH '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.hdh=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMhdh" +routingDomain='["geosite:hbo","geosite:disney","geosite:hulu"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $4 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.hdh)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.hdh' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMhdh" + routingDomain='["geosite:hbo","geosite:disney","geosite:hulu"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $5 ]] && [[ $5 != "0" ]]; then +nodeSMnumTVB=$[$5-1] +address=$(jq -r --argjson nodecheck $nodeSMnumTVB '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumTVB '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumTVB '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumTVB '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.tvb=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMtvb" +routingDomain='["geosite:tvb"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $5 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.tvb)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.tvb' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMtvb" + routingDomain='["geosite:tvb"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $6 ]] && [[ $6 != "0" ]]; then +nodeSMnumBahamut=$[$6-1] +address=$(jq -r --argjson nodecheck $nodeSMnumBahamut '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumBahamut '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumBahamut '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumBahamut '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.bahamut=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMbahamut" +routingDomain='["geosite:bahamut"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $6 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.bahamut)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.bahamut' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMbahamut" + routingDomain='["geosite:bahamut"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $7 ]] && [[ $7 != "0" ]]; then +nodeSMnumOpenai=$[$7-1] +address=$(jq -r --argjson nodecheck $nodeSMnumOpenai '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumOpenai '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumOpenai '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumOpenai '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.openai=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMopenai" +routingDomain='["geosite:openai"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $7 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.openai)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else +address=$(jq -r '.v2nodeDIV.nodeSM.openai' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMopenai" + routingDomain='["geosite:openai"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $8 ]] && [[ $8 != "0" ]]; then +nodeSMnumApple=$[$8-1] +address=$( + jq -r --argjson nodecheck $nodeSMnumApple '.v2node | to_entries[] | select(.key == $nodecheck) | .value.domain' /opt/de_GWD/0conf) +tls=$(jq -r --argjson nodecheck $nodeSMnumApple '.v2node | to_entries[] | select(.key == $nodecheck) | .value.tls' /opt/de_GWD/0conf) +uuid=$(jq -r --argjson nodecheck $nodeSMnumApple '.v2node | to_entries[] | select(.key == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) +path=$(jq -r --argjson nodecheck $nodeSMnumApple '.v2node | to_entries[] | select(.key == $nodecheck) | .value.path' /opt/de_GWD/0conf) +jq --arg address $address '.v2nodeDIV.nodeSM.apple=$address' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +tag="nodeSMapple" +routingDomain='["geosite:apple","geosite:apple-ads","geosite:apple-dev","geosite:apple-update","geosite:icloud","geosite:apple@cn","geosite:apple-cn"]' +/opt/de_GWD/ui-V2routingDomain $tag $routingDomain +/opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path +elif [[ $8 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.apple)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + /opt/de_GWD/ui-V2routingDomain 'direct' '["geosite:apple","geosite:apple-ads","geosite:apple-dev","geosite:apple-update","geosite:icloud","geosite:apple@cn","geosite:apple-cn"]' +else +address=$(jq -r '.v2nodeDIV.nodeSM.apple' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + if [[ -n $address ]]; then + sed -i '/apple.china.conf/d' /opt/de_GWD/smartdns/smartdns.conf && systemctl restart smartdns + tls=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.tls' /opt/de_GWD/0conf) + uuid=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.uuid' /opt/de_GWD/0conf) + path=$(jq -r --arg nodecheck $address '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .value.path' /opt/de_GWD/0conf) + tag="nodeSMapple" + routingDomain='["geosite:apple","geosite:apple-ads","geosite:apple-dev","geosite:apple-update","geosite:icloud","geosite:apple@cn","geosite:apple-cn"]' + /opt/de_GWD/ui-V2routingDomain $tag $routingDomain + /opt/de_GWD/ui-V2outbound $tag $address $tls $uuid $path + fi +fi + +if [[ -n $9 ]] && [[ $9 != "0" ]]; then +jq '.v2nodeDIV.nodeSM.steam="proxy"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +elif [[ $9 = "0" ]]; then + jq 'del(.v2nodeDIV.nodeSM.steam)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + /opt/de_GWD/ui-V2routingDomain 'direct' '["geosite:category-games@cn"]' +else + if [[ -z $(jq -r '.v2nodeDIV.nodeSM.steam' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then + /opt/de_GWD/ui-V2routingDomain 'direct' '["geosite:category-games@cn"]' + fi +fi + +/opt/de_GWD/ui-submitListBWsm + +if [[ $2 = "0" ]] && [[ $3 = "0" ]] && [[ $4 = "0" ]] && [[ $5 = "0" ]] && [[ $6 = "0" ]] && [[ $7 = "0" ]] && [[ $8 = "0" ]]; then + jq '.v2nodeDIV.nodeSM.status="off"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +else + jq '.v2nodeDIV.nodeSM.status="on"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +fi + + +if [[ $1 = "r" ]]; then + systemctl restart mosdns + systemctl restart vtrui +fi + +chmod 666 /opt/de_GWD/0conf diff --git a/resource/client/ui-script/ui-NodeSMcheck b/resource/client/ui-script/ui-NodeSMcheck new file mode 100755 index 000000000..85037e1ba --- /dev/null +++ b/resource/client/ui-script/ui-NodeSMcheck @@ -0,0 +1,191 @@ +#!/bin/bash +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMyoutube") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMyoutube") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMnetflix") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMnetflix") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMhdh") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMhdh") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMtvb") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMtvb") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMbahamut") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMbahamut") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMopenai") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMopenai") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +domain=$(jq -r '.outbounds[] | select(.tag == "nodeSMapple") | .settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[] | select(.tag == "nodeSMapple") | .settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck="$domain:$port" +fi + +checkNum=$(jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf) +checkName=$(jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf) + +if [[ -z $checkNum ]]; then +echo "0" +else +echo $((checkNum+=1)) +fi + +if [[ -z $checkName ]]; then +echo "-none-" +else +echo $checkName +fi + + + +if [[ -z $(jq -r '.v2nodeDIV.nodeSM.steam' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then +echo "0" +echo "-none-" +else +echo "1" +echo "默认代理" +fi diff --git a/resource/client/ui-script/ui-NodeSave b/resource/client/ui-script/ui-NodeSave new file mode 100755 index 000000000..599220eda --- /dev/null +++ b/resource/client/ui-script/ui-NodeSave @@ -0,0 +1,41 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Collect V2 node${cRES}\r\c" + +>/opt/de_GWD/mosdns/domains_nodes +>/opt/de_GWD/nftables/IP_V2NODE +jq -r '.v2node[].domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | cut -d: -f1 | sort | uniq | xargs -n 1 | sed '/^\s*$/d' | while read line; do + echo $line >>/opt/de_GWD/mosdns/domains_nodes + dig @127.0.0.1 $line -4p 5332 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | sed '/^\s*$/d' >>/opt/de_GWD/nftables/IP_V2NODE +done + +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_V2NODE +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_V2NODE +nft flush set ip de_GWD V2NODE +cat << EOF >/opt/de_GWD/nftables/SET_V2NODE.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set V2NODE { + type ipv4_addr + flags interval + auto-merge + elements = { $(cat /opt/de_GWD/nftables/IP_V2NODE) } + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_V2NODE.nft +/opt/de_GWD/nftables/SET_V2NODE.nft + +[[ $1 = "r" ]] && systemctl restart mosdns + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Collect V2 node${cRES}" diff --git a/resource/client/ui-script/ui-RproxyCsave b/resource/client/ui-script/ui-RproxyCsave new file mode 100755 index 000000000..e66bd1150 --- /dev/null +++ b/resource/client/ui-script/ui-RproxyCsave @@ -0,0 +1,147 @@ +#!/bin/bash +rm -rf /opt/de_GWD/RproxyC +mkdir -p /opt/de_GWD/RproxyC +cp -f /opt/de_GWD/vtrui/vtrui /opt/de_GWD/RproxyC/RproxyC +chmod +x /opt/de_GWD/RproxyC/RproxyC + +RproxyCoutStatus=$(jq -r '.FORWARD.Rproxy.client.outStatus' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxyCmappingStatus=$(jq -r '.FORWARD.Rproxy.client.mappingStatus' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +RproxyStunnelAddress=$(jq -r '.FORWARD.Rproxy.client.tunnel.address' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxyStunnelUUID=$(jq -r '.FORWARD.Rproxy.client.tunnel.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxyCmappingList=$(jq -r '.FORWARD.Rproxy.client.mapping' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +domain=$(echo -e $RproxyStunnelAddress | cut -d: -f1) +port=$(echo -e $RproxyStunnelAddress | cut -d: -f2 | grep '^[[:digit:]]*$') +[[ -z $port ]] && port="443" + +cat << EOF >/opt/de_GWD/RproxyC/config.json +{ + "log": { + "access":"none", + "error":"none", + "loglevel":"none" + }, + "dns":{ + "queryStrategy":"UseIP", + "disableCache":true, + "servers":["tcp+local://127.0.0.1:53"] + }, + "routing":{ + "rules":[ + {"type":"field","inboundTag":["bridge"],"domain":["full:reverse.localhost"],"outboundTag":"reverseTunnel"} + ] + }, + "reverse": { + "bridges": [{ + "tag": "bridge", + "domain": "reverse.localhost" + }] + }, + "outbounds": [ + { + "tag": "reverseTunnel", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$RproxyStunnelUUID", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } + } + ] +} +EOF + + +if [[ $RproxyCmappingStatus = "on" ]]; then + +len=$(echo $RproxyCmappingList | jq length) + +for (( i=0; i<$len; i++ )); do +extPort=$(echo $RproxyCmappingList | jq -r --argjson i "$i" '.[$i].extPort') +extProtocol=$(echo $RproxyCmappingList | jq -r --argjson i "$i" '.[$i].extProtocol') +intIP=$(echo $RproxyCmappingList | jq -r --argjson i "$i" '.[$i].intIP') +intPort=$(echo $RproxyCmappingList | jq -r --argjson i "$i" '.[$i].intPort') + +RontingMapping=`cat << EOF + {"type":"field","inboundTag":["bridge"],"port":"$extPort","network":"$extProtocol","outboundTag":"mapping$i"} +EOF +` + +OBmapping=`cat << EOF + { + "tag": "mapping$i", + "protocol": "freedom", + "settings": { + "redirect": "$intIP:$intPort" + } + } +EOF +` +jq --argjson RontingMapping "$RontingMapping" '.routing.rules+=[$RontingMapping]' /opt/de_GWD/RproxyC/config.json |\ +jq --argjson OBmapping "$OBmapping" '.outbounds+=[$OBmapping]' | sponge /opt/de_GWD/RproxyC/config.json +done +fi + + +if [[ $RproxyCoutStatus = "on" ]]; then +RontingOut=`cat << EOF + {"type":"field","inboundTag":["bridge"],"outboundTag":"directOut"} +EOF +` + +OBout=`cat << EOF + { + "tag": "directOut", + "protocol": "freedom" + } +EOF +` + +jq --argjson RontingOut "$RontingOut" '.routing.rules+=[$RontingOut]' /opt/de_GWD/RproxyC/config.json |\ +jq --argjson OBout "$OBout" '.outbounds+=[$OBout]' | sponge /opt/de_GWD/RproxyC/config.json +fi + +chmod 666 /opt/de_GWD/RproxyC/config.json +chmod 644 /var/www/ssl/*.key + +rm -rf /lib/systemd/system/RproxyC.service +cat << "EOF" >/etc/systemd/system/RproxyC.service +[Unit] +Description=Rproxy client +After=network.target nss-lookup.target + +[Service] +User=root +Type=simple +ExecStart=/opt/de_GWD/RproxyC/RproxyC run -config /opt/de_GWD/RproxyC/config.json +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl enable RproxyC >/dev/null +systemctl restart RproxyC diff --git a/resource/client/ui-script/ui-RproxyCstop b/resource/client/ui-script/ui-RproxyCstop new file mode 100755 index 000000000..e012abafe --- /dev/null +++ b/resource/client/ui-script/ui-RproxyCstop @@ -0,0 +1,6 @@ +#!/bin/bash +systemctl disable --now RproxyC >/dev/null +rm -rf /lib/systemd/system/RproxyC.service +rm -rf /etc/systemd/system/RproxyC.service +rm -rf /opt/de_GWD/RproxyC +systemctl daemon-reload >/dev/null diff --git a/resource/client/ui-script/ui-RproxySsave b/resource/client/ui-script/ui-RproxySsave new file mode 100755 index 000000000..17cd7cb48 --- /dev/null +++ b/resource/client/ui-script/ui-RproxySsave @@ -0,0 +1,128 @@ +#!/bin/bash +rm -rf /opt/de_GWD/RproxyS +mkdir -p /opt/de_GWD/RproxyS +cp -f /opt/de_GWD/vtrui/vtrui /opt/de_GWD/RproxyS/RproxyS +chmod +x /opt/de_GWD/RproxyS/RproxyS + +RproxySinStatus=$(jq -r '.FORWARD.Rproxy.server.inStatus' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxySmappingStatus=$(jq -r '.FORWARD.Rproxy.server.mappingStatus' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +RproxyStunnelPort=$(jq -r '.FORWARD.Rproxy.server.tunnel.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxyStunnelUUID=$(jq -r '.FORWARD.Rproxy.server.tunnel.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxySinUUID=$(jq -r '.FORWARD.Rproxy.server.inUUID[].RproxyS0uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +RproxySmappingList=$(jq -r '.FORWARD.Rproxy.server.mapping' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +cat << EOF >/opt/de_GWD/RproxyS/config.json +{ + "log": { + "access":"none", + "error":"none", + "loglevel":"none" + }, + "dns":{ + "queryStrategy":"UseIP", + "disableCache":true, + "servers":["tcp+local://127.0.0.1:53"] + }, + "routing":{ + "rules":[ + {"type":"field","inboundTag":["reverseTunnel"],"domain":["full:reverse.localhost"],"outboundTag":"portal"}, + {"type":"field","inboundTag":["reverseTunnel"],"outboundTag":"portal"} + ] + }, + "reverse": { + "portals": [{ + "tag": "portal", + "domain": "reverse.localhost" + }] + }, + "inbounds": [ + { + "tag": "reverseTunnel", + "port": $RproxyStunnelPort, + "protocol": "vmess", + "settings":{ + "clients":[ + { + "id":"$RproxyStunnelUUID", + "alterId": 0 + } + ] + }, + "streamSettings": { + "network": "tcp" + } + } + ] +} +EOF + + +if [[ $RproxySinStatus = "on" ]]; then +for uuid in $RproxySinUUID; do +uuidStr='{"id":"'$uuid'", "alterId":0}' +jq --argjson uuidStr "$uuidStr" '.inbounds[0].settings.clients+=[$uuidStr]' /opt/de_GWD/RproxyS/config.json | sponge /opt/de_GWD/RproxyS/config.json +done + +uniqueClient=$(jq -r '.inbounds[0].settings.clients | unique' /opt/de_GWD/RproxyS/config.json 2>/dev/null | grep -v '^null$') +jq --argjson uniqueClient "$uniqueClient" '.inbounds[0].settings.clients=$uniqueClient' /opt/de_GWD/RproxyS/config.json | sponge /opt/de_GWD/RproxyS/config.json +fi + + +if [[ $RproxySmappingStatus = "on" ]]; then + +len=$(echo $RproxySmappingList | jq length) + +for (( i=0; i<$len; i++ )); do +port=$(echo $RproxySmappingList | jq -r --argjson i "$i" '.[$i].port') +protocol=$(echo $RproxySmappingList | jq -r --argjson i "$i" '.[$i].protocol') + +RontingMapping=`cat << EOF + {"type":"field","inboundTag":["mapping$i"],"outboundTag":"portal"} +EOF +` + +IBmapping=`cat << EOF + { + "tag": "mapping$i", + "port": $port, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1", + "port": $port, + "network": "$protocol" + } + } +EOF +` +jq --argjson RontingMapping "$RontingMapping" '.routing.rules+=[$RontingMapping]' /opt/de_GWD/RproxyS/config.json |\ +jq --argjson IBmapping "$IBmapping" '.inbounds+=[$IBmapping]' | sponge /opt/de_GWD/RproxyS/config.json +done +fi + +chmod 666 /opt/de_GWD/RproxyS/config.json +chmod 644 /var/www/ssl/*.key + +rm -rf /lib/systemd/system/RproxyS.service +cat << "EOF" >/etc/systemd/system/RproxyS.service +[Unit] +Description=Rproxy Service +After=network.target nss-lookup.target + +[Service] +User=root +Type=simple +ExecStart=/opt/de_GWD/RproxyS/RproxyS run -config /opt/de_GWD/RproxyS/config.json +Restart=always +RestartSec=2 +TimeoutStopSec=5 + +AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl enable RproxyS >/dev/null 2>&1 +systemctl restart RproxyS diff --git a/resource/client/ui-script/ui-RproxySstop b/resource/client/ui-script/ui-RproxySstop new file mode 100755 index 000000000..e6645de29 --- /dev/null +++ b/resource/client/ui-script/ui-RproxySstop @@ -0,0 +1,6 @@ +#!/bin/bash +systemctl disable --now RproxyS >/dev/null +rm -rf /lib/systemd/system/RproxyS.service +rm -rf /etc/systemd/system/RproxyS.service +rm -rf /opt/de_GWD/RproxyS +systemctl daemon-reload >/dev/null diff --git a/resource/client/ui-script/ui-V2outbound b/resource/client/ui-script/ui-V2outbound new file mode 100755 index 000000000..210bb4d53 --- /dev/null +++ b/resource/client/ui-script/ui-V2outbound @@ -0,0 +1,108 @@ +#!/bin/bash +tag=$1 +address=$2 +tls=$3 +uuid=$4 +path=$5 + +if [[ -z $tag ]] || [[ -z $address ]] || [[ -z $uuid ]]; then +exit +fi + +domain=$(echo $address | cut -d: -f1) +port=$(echo $address | cut -d: -f2 | grep '^[[:digit:]]*$') +[[ -z $port ]] && port="443" +[[ -z $tls ]] && tls=$domain + + +if [[ $tag = "default" ]]; then +muxEnable="true" +muxCconcurrency="8" +else +muxEnable="false" +muxCconcurrency="1" +fi + + +if [[ -z $path ]]; then +OBadd=`cat << EOF + { + "tag": "$tag", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + }, + "mux": { + "enabled": $muxEnable, + "concurrency": $muxCconcurrency + } + } +EOF +` +else +OBadd=`cat << EOF + { + "tag": "$tag", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "path": "$path", + "headers": { + "Host": "$tls" + } + }, + "security": "tls", + "tlsSettings": { + "serverName": "$tls", + "allowInsecure": false + }, + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + }, + "mux": { + "enabled": $muxEnable, + "concurrency": $muxCconcurrency + } + } +EOF +` +fi + +jq --argjson OBadd "$OBadd" '.outbounds+=[$OBadd]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json diff --git a/resource/client/ui-script/ui-V2routingDomain b/resource/client/ui-script/ui-V2routingDomain new file mode 100755 index 000000000..929068a19 --- /dev/null +++ b/resource/client/ui-script/ui-V2routingDomain @@ -0,0 +1,17 @@ +#!/bin/bash +if [[ -n $1 ]] && [[ -n $2 ]]; then +tag=$1 +domain=$2 + +RoutingADD=`cat << EOF +{ + "type": "field", + "domain": $domain, + "network": "tcp,udp", + "outboundTag": "$tag" +} +EOF +` + +jq --argjson RoutingADD "$RoutingADD" '.routing.rules+=[$RoutingADD]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json +fi diff --git a/resource/client/ui-script/ui-V2routingIP b/resource/client/ui-script/ui-V2routingIP new file mode 100755 index 000000000..60e43f0cc --- /dev/null +++ b/resource/client/ui-script/ui-V2routingIP @@ -0,0 +1,17 @@ +#!/bin/bash +if [[ -n $1 ]] && [[ -n $2 ]]; then +tag=$1 +IP=$2 + +RoutingADD=`cat << EOF +{ + "type": "field", + "ip": $IP, + "network": "tcp,udp", + "outboundTag": "$tag" +} +EOF +` + +jq --argjson RoutingADD "$RoutingADD" '.routing.rules+=[$RoutingADD]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json +fi diff --git a/resource/client/ui-script/ui-V2routingSip b/resource/client/ui-script/ui-V2routingSip new file mode 100755 index 000000000..ca891f3a3 --- /dev/null +++ b/resource/client/ui-script/ui-V2routingSip @@ -0,0 +1,17 @@ +#!/bin/bash +if [[ -n $1 ]] && [[ -n $2 ]]; then +tag=$1 +IP=$2 + +RoutingADD=`cat << EOF +{ + "type": "field", + "source": $IP, + "network": "tcp,udp", + "outboundTag": "$tag" +} +EOF +` + +jq --argjson RoutingADD "$RoutingADD" '.routing.rules+=[$RoutingADD]' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json +fi diff --git a/resource/client/ui-script/ui-WGgenCkey b/resource/client/ui-script/ui-WGgenCkey new file mode 100755 index 000000000..e18454c4f --- /dev/null +++ b/resource/client/ui-script/ui-WGgenCkey @@ -0,0 +1,19 @@ +#!/bin/bash +i=$1 + +mkdir -p /etc/wireguard +cd /etc/wireguard + +wg genkey | tee cprivatekey | wg pubkey > cpublickey + +cprivatekey=$(cat /etc/wireguard/cprivatekey) +cpublickey=$(cat /etc/wireguard/cpublickey) + +jq --argjson i "$i" --arg cprivatekey "$cprivatekey" '.wireguard.clients[$i].cprivatekey=$cprivatekey' /opt/de_GWD/0conf |\ +jq --argjson i "$i" --arg cpublickey "$cpublickey" '.wireguard.clients[$i].cpublickey=$cpublickey' | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +rm -rf /etc/wireguard/c*key + +echo $cprivatekey +echo $cpublickey \ No newline at end of file diff --git a/resource/client/ui-script/ui-WGgenSkey b/resource/client/ui-script/ui-WGgenSkey new file mode 100755 index 000000000..7b7d213c9 --- /dev/null +++ b/resource/client/ui-script/ui-WGgenSkey @@ -0,0 +1,14 @@ +#!/bin/bash +mkdir -p /etc/wireguard +cd /etc/wireguard + +wg genkey | tee sprivatekey | wg pubkey > spublickey + +sprivatekey=$(cat /etc/wireguard/sprivatekey) +spublickey=$(cat /etc/wireguard/spublickey) + +jq --arg sprivatekey "$sprivatekey" '.wireguard.server.sprivatekey=$sprivatekey' /opt/de_GWD/0conf |\ +jq --arg spublickey "$spublickey" '.wireguard.server.spublickey=$spublickey' | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +rm -rf /etc/wireguard/s*key diff --git a/resource/client/ui-script/ui-WGoff b/resource/client/ui-script/ui-WGoff new file mode 100755 index 000000000..94d9a751c --- /dev/null +++ b/resource/client/ui-script/ui-WGoff @@ -0,0 +1,10 @@ +#!/bin/bash +systemctl stop wg-quick@wg0 >/dev/null 2>&1 +systemctl disable wg-quick@wg0 >/dev/null 2>&1 + +ethernetnum=$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device' | xargs -n 1 | grep -v 'virtual' | grep -v 'ifb' | awk -F'/' '{print$NF}' | head -n1) +sed -i "/PIHOLE_INTERFACE=/c\PIHOLE_INTERFACE=$ethernetnum,ifb4$ethernetnum" /etc/pihole/setupVars.conf +sed -i "/interface=/c\interface=$ethernetnum,ifb4$ethernetnum" /etc/dnsmasq.d/01-pihole.conf +pihole restartdns + +/etc/rc_online.local diff --git a/resource/client/ui-script/ui-WGon b/resource/client/ui-script/ui-WGon new file mode 100755 index 000000000..a863bcdb8 --- /dev/null +++ b/resource/client/ui-script/ui-WGon @@ -0,0 +1,83 @@ +#!/bin/bash +WGaddress=$(jq -r '.wireguard.server.WGaddress' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +WGport=$(jq -r '.wireguard.server.WGport' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +sprivatekey=$(jq -r '.wireguard.server.sprivatekey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +spublickey=$(jq -r '.wireguard.server.spublickey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +clientsNUM=$(jq -r '.wireguard.clients | length' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +clientsNUMinvalid=$(jq -r '.wireguard.clients[].cprivatekey' /opt/de_GWD/0conf | grep '^undefined$' | wc -l) +clientsNUMgood=$[$clientsNUM-$clientsNUMinvalid] + +rm -rf /etc/wireguard/client*.conf + +cat << EOF >/etc/wireguard/wg0.conf +[Interface] +PrivateKey = $sprivatekey +Address = 172.16.66.1/32 +ListenPort = $WGport +DNS = 127.0.0.1 +MTU = 1420 +EOF + +for ((i=0; i<$clientsNUMgood; i++)); do +cat << EOF >>/etc/wireguard/wg0.conf + +[Peer] +PublicKey = $(jq -r --argjson i "$i" '.wireguard.clients[$i].cpublickey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +AllowedIPs = 172.16.66.$[$i+11]/32 +EOF + +cat << EOF >/etc/wireguard/client$[$i+1].conf +[Interface] +PrivateKey = $(jq -r --argjson i "$i" '.wireguard.clients[$i].cprivatekey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +Address = 172.16.66.$[$i+11]/32 +DNS = 172.16.66.1 +MTU = 1400 + +[Peer] +PublicKey = $spublickey +Endpoint = $WGaddress:$WGport +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 15 +EOF +done +chmod 600 /etc/wireguard/wg0.conf +chmod 600 /etc/wireguard/client*.conf + +rm -rf /lib/systemd/system/wg-quick@.service +cat << "EOF" >/etc/systemd/system/wg-quick@.service +[Unit] +Description=WireGuard via wg-quick(8) for %I +After=network-online.target nss-lookup.target +Wants=network-online.target nss-lookup.target +PartOf=wg-quick.target + +[Service] +User=root +Type=oneshot +ExecStart=/usr/bin/wg-quick up %i +ExecStartPost=/etc/rc_online.local +ExecStop=/usr/bin/wg-quick down %i +ExecStopPost=/etc/rc_online.local +ExecReload=/bin/bash -c 'exec /usr/bin/wg syncconf %i <(exec /usr/bin/wg-quick strip %i)' +Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload >/dev/null +systemctl enable wg-quick@wg0 >/dev/null 2>&1 +systemctl restart wg-quick@wg0 + +sed -i '/net.ipv4.ip_forward =/c\net.ipv4.ip_forward = 1 +net.ipv4.conf.all.forwarding = 1 +net.ipv4.conf.default.forwarding = 1' /etc/sysctl.conf +sysctl -p >/dev/null 2>&1 + +ethernetnum=$(find /sys/class/net ! -type d | xargs --max-args=1 realpath | grep 'device' | xargs -n 1 | grep -v 'virtual' | grep -v 'ifb' | awk -F'/' '{print$NF}' | head -n1) +sed -i "/PIHOLE_INTERFACE=/c\PIHOLE_INTERFACE=$ethernetnum,ifb4$ethernetnum,wg0,ifb4wg0" /etc/pihole/setupVars.conf +sed -i "/interface=/c\interface=$ethernetnum,ifb4$ethernetnum,wg0,ifb4wg0" /etc/dnsmasq.d/01-pihole.conf +pihole restartdns + +/etc/rc_online.local diff --git a/resource/client/ui-script/ui-autoUpdateHour b/resource/client/ui-script/ui-autoUpdateHour new file mode 100755 index 000000000..f6692d556 --- /dev/null +++ b/resource/client/ui-script/ui-autoUpdateHour @@ -0,0 +1,46 @@ +#!/bin/bash +if [[ $1 = "off" ]]; then +crontab -l 2>/dev/null > /tmp/now.cron +sed -i '/autoUpdate/d' /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron +rm -rf /opt/de_GWD/autoUpdate +else +cat << "EOF" >/opt/de_GWD/autoUpdate +#!/bin/bash +localVer=$(awk 'NR==1' /var/www/html/act/version.php) +remoteVer=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/de_GWD/main/version.php | head -n 1) + +echo $localVer >/tmp/de_GWD_Ver +echo $remoteVer >>/tmp/de_GWD_Ver + +VerCP=$(cat /tmp/de_GWD_Ver | sort -rV | uniq | awk NR==2) + +if [[ $VerCP = $localVer ]]; then +systemctl stop php7.4-fpm + +rm -rf /tmp/autoUpdate +wget -cqO /tmp/autoUpdate https://raw.githubusercontent.com/jacyl4/de_GWD/main/client + +if [[ $(du -sk /tmp/autoUpdate 2>/dev/null | awk '{print$1}') -gt 70 ]]; then +sed -i '$d' /tmp/autoUpdate +echo "updateGWD auto" >>/tmp/autoUpdate +chmod +x /tmp/autoUpdate +/tmp/autoUpdate +rm -rf /tmp/autoUpdate +fi + +systemctl restart php7.4-fpm +fi + +rm -rf /tmp/de_GWD_Ver +rm -rf /tmp/autoUpdate +EOF +chmod +x /opt/de_GWD/autoUpdate + +crontab -l 2>/dev/null > /tmp/now.cron +sed -i '/autoUpdate/d' /tmp/now.cron +echo "0 $1 * * * /opt/de_GWD/autoUpdate" >> /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron +fi diff --git a/resource/client/ui-script/ui-block53off b/resource/client/ui-script/ui-block53off new file mode 100755 index 000000000..b6b0b5289 --- /dev/null +++ b/resource/client/ui-script/ui-block53off @@ -0,0 +1,3 @@ +#!/bin/bash +sed -i '/meta l4proto { tcp, udp } th dport 53 drop/d' /opt/de_GWD/nftables/default.nft +systemctl restart nftables diff --git a/resource/client/ui-script/ui-block53on b/resource/client/ui-script/ui-block53on new file mode 100755 index 000000000..6292dd288 --- /dev/null +++ b/resource/client/ui-script/ui-block53on @@ -0,0 +1,4 @@ +#!/bin/bash +sed -i '/meta l4proto { tcp, udp } th dport 53 drop/d' /opt/de_GWD/nftables/default.nft +sed -i "/# Drop 53 in$/a\meta l4proto { tcp, udp } th dport 53 drop" /opt/de_GWD/nftables/default.nft +systemctl restart nftables diff --git a/resource/client/ui-script/ui-changeNodeSS b/resource/client/ui-script/ui-changeNodeSS new file mode 100755 index 000000000..02a3aa339 --- /dev/null +++ b/resource/client/ui-script/ui-changeNodeSS @@ -0,0 +1,33 @@ +#!/bin/bash +ssAddress=$(jq -r '.v2nodeDIV.ss.ssAddress' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +ssPort=$(jq -r '.v2nodeDIV.ss.ssPort' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +ssMethod=$(jq -r '.v2nodeDIV.ss.ssMethod' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +ssSecure=$(jq -r '.v2nodeDIV.ss.ssSecure' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +OBss=`cat << EOF +{ + "tag": "ss", + "protocol": "shadowsocks", + "settings": { + "servers": [ + { + "address": "$ssAddress", + "port": $ssPort, + "method": "$ssMethod", + "password": "$ssSecure", + "level": 1 + } + ] + }, + "streamSettings": { + "sockopt": { + "mark": 255 + } + } +} +EOF +` + +jq --argjson OBss "$OBss" '.outbounds[0]=$OBss' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + +[[ $1 = "r" ]] && systemctl restart vtrui >/dev/null diff --git a/resource/client/ui-script/ui-changeNodeSS0 b/resource/client/ui-script/ui-changeNodeSS0 new file mode 100755 index 000000000..0d796c26c --- /dev/null +++ b/resource/client/ui-script/ui-changeNodeSS0 @@ -0,0 +1,85 @@ +#!/bin/bash +domain=$(jq -r '.update.v2node.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +tls=$(jq -r '.update.v2node.tls' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +port=$(jq -r '.update.v2node.port' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +uuid=$(jq -r '.update.v2node.uuid' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +path=$(jq -r '.update.v2node.path' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +[[ -z $tls ]] && tls=$domain + +if [[ -z $path ]]; then +OBdefault=`cat << EOF + { + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } + } +EOF +` +else +OBdefault=`cat << EOF +{ + "tag": "default", + "protocol": "vmess", + "settings": { + "vnext": [ + { + "address": "$domain", + "port": $port, + "users": [ + { + "id": "$uuid", + "alterId": 0, + "security": "auto" + } + ] + } + ] + }, + "streamSettings": { + "network": "ws", + "wsSettings": { + "path": "$path", + "headers": { + "Host": "$tls" + } + }, + "security": "tls", + "tlsSettings": { + "serverName": "$tls", + "allowInsecure": false + }, + "sockopt": { + "mark": 255, + "tcpFastOpen": true + } + } +} +EOF +` +fi + +jq --argjson OBdefault "$OBdefault" '.outbounds[0]=$OBdefault' /opt/de_GWD/vtrui/config.json | sponge /opt/de_GWD/vtrui/config.json + +systemctl restart vtrui diff --git a/resource/client/ui-script/ui-checkDDNS3322 b/resource/client/ui-script/ui-checkDDNS3322 new file mode 100755 index 000000000..f755983ee --- /dev/null +++ b/resource/client/ui-script/ui-checkDDNS3322 @@ -0,0 +1,6 @@ +#!/bin/bash +if [[ $(crontab -l 2>/dev/null) =~ "ddns3322updateIP" ]]; then + echo "success" +else + echo "outline-secondary" +fi diff --git a/resource/client/ui-script/ui-checkDDNScf b/resource/client/ui-script/ui-checkDDNScf new file mode 100755 index 000000000..e5629361a --- /dev/null +++ b/resource/client/ui-script/ui-checkDDNScf @@ -0,0 +1,6 @@ +#!/bin/bash +if [[ $(crontab -l 2>/dev/null) =~ "ddnsCFupdateIP" ]]; then + echo "success" +else + echo "outline-secondary" +fi diff --git a/resource/client/ui-script/ui-checkDhcp b/resource/client/ui-script/ui-checkDhcp new file mode 100755 index 000000000..e860051cb --- /dev/null +++ b/resource/client/ui-script/ui-checkDhcp @@ -0,0 +1,6 @@ +#!/bin/bash +if [[ $(ls /etc/dnsmasq.d) =~ "dhcp" ]]; then + echo "success" +else + echo "outline-secondary" +fi diff --git a/resource/client/ui-script/ui-checkEditionARM b/resource/client/ui-script/ui-checkEditionARM new file mode 100755 index 000000000..bcfd0f4af --- /dev/null +++ b/resource/client/ui-script/ui-checkEditionARM @@ -0,0 +1,2 @@ +#!/bin/bash +[[ $(dpkg --print-architecture) = "arm64" ]] && echo "ARM" diff --git a/resource/client/ui-script/ui-checkFWD1 b/resource/client/ui-script/ui-checkFWD1 new file mode 100755 index 000000000..b2d374bf1 --- /dev/null +++ b/resource/client/ui-script/ui-checkFWD1 @@ -0,0 +1,16 @@ +#!/bin/bash +if [[ -f "/opt/de_GWD/vtrui1/config.json" ]]; then +domain=$(jq -r '.outbounds[0].settings.vnext[0].address' /opt/de_GWD/vtrui1/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[0].settings.vnext[0].port' /opt/de_GWD/vtrui1/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck=$domain:$port +fi + +jq -r --arg nodecheck $nodecheck '.v2node[] | select(.domain == $nodecheck) | .name' /opt/de_GWD/0conf + +echo $nodecheck | grep -v '^:' +rm -rf /tmp/vtruiDomains +fi diff --git a/resource/client/ui-script/ui-checkNode b/resource/client/ui-script/ui-checkNode new file mode 100755 index 000000000..a372902ad --- /dev/null +++ b/resource/client/ui-script/ui-checkNode @@ -0,0 +1,11 @@ +#!/bin/bash +domain=$(jq -r '.outbounds[0].settings.vnext[0].address' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') +port=$(jq -r '.outbounds[0].settings.vnext[0].port' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $port = "443" ]]; then +nodecheck=$domain +else +nodecheck=$domain:$port +fi + +jq -r --arg nodecheck $nodecheck '.v2node | to_entries[] | select(.value.domain == $nodecheck) | .key' /opt/de_GWD/0conf diff --git a/resource/client/ui-script/ui-checkNodeSS b/resource/client/ui-script/ui-checkNodeSS new file mode 100755 index 000000000..234516532 --- /dev/null +++ b/resource/client/ui-script/ui-checkNodeSS @@ -0,0 +1,8 @@ +#!/bin/bash +checkSS=$(jq -r '.outbounds[0].tag' /opt/de_GWD/vtrui/config.json 2>/dev/null | grep -v '^null$') + +if [[ $checkSS = "ss" ]]; then +echo "btn-success" +else +echo "btn-outline-secondary" +fi diff --git a/resource/client/ui-script/ui-checkWG b/resource/client/ui-script/ui-checkWG new file mode 100755 index 000000000..cc7a2b4e9 --- /dev/null +++ b/resource/client/ui-script/ui-checkWG @@ -0,0 +1,2 @@ +#!/bin/bash +[[ -n $(find /sys/class/net | awk -F'/' '{print$NF}' | grep '^wg0') ]] && echo "success" diff --git a/resource/client/ui-script/ui-check_ssl b/resource/client/ui-script/ui-check_ssl new file mode 100755 index 000000000..56361716e --- /dev/null +++ b/resource/client/ui-script/ui-check_ssl @@ -0,0 +1,2 @@ +#!/bin/bash +openssl x509 -enddate -noout -in /var/www/ssl/de_GWD.cer | sed 's/notAfter=//' diff --git a/resource/client/ui-script/ui-ddns3322off b/resource/client/ui-script/ui-ddns3322off new file mode 100755 index 000000000..a62f1579c --- /dev/null +++ b/resource/client/ui-script/ui-ddns3322off @@ -0,0 +1,5 @@ +#!/bin/bash +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/ui-ddns3322/d' /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron diff --git a/resource/client/ui-script/ui-ddns3322on b/resource/client/ui-script/ui-ddns3322on new file mode 100755 index 000000000..cf8828283 --- /dev/null +++ b/resource/client/ui-script/ui-ddns3322on @@ -0,0 +1,8 @@ +#!/bin/bash +/opt/de_GWD/ui-ddns3322updateIP + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/ui-ddns3322/d' /tmp/now.cron +echo '*/1 * * * * /opt/de_GWD/ui-ddns3322updateIP >/dev/null 2>&1' >>/tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron diff --git a/resource/client/ui-script/ui-ddns3322updateIP b/resource/client/ui-script/ui-ddns3322updateIP new file mode 100755 index 000000000..07c0d4036 --- /dev/null +++ b/resource/client/ui-script/ui-ddns3322updateIP @@ -0,0 +1,10 @@ +#!/bin/bash +wanIP=$(/opt/de_GWD/ui-wanIP_cn) + +domain=$(jq -r '.ddns.ddns3322.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +user=$(jq -r '.ddns.ddns3322.user' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +pwd=$(jq -r '.ddns.ddns3322.pwd' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +domainip=$(dig $domain +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) + +[[ $wanIP != $domainip ]] && curl -u $user:$pwd "http://www.3322.org/dyndns/update?hostname=$domain&myip=$wanIP" diff --git a/resource/client/ui-script/ui-ddnsCFoff b/resource/client/ui-script/ui-ddnsCFoff new file mode 100755 index 000000000..b76a5e8f5 --- /dev/null +++ b/resource/client/ui-script/ui-ddnsCFoff @@ -0,0 +1,5 @@ +#!/bin/bash +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/ui-ddnsCF/d' /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron diff --git a/resource/client/ui-script/ui-ddnsCFon b/resource/client/ui-script/ui-ddnsCFon new file mode 100755 index 000000000..041207a9b --- /dev/null +++ b/resource/client/ui-script/ui-ddnsCFon @@ -0,0 +1,8 @@ +#!/bin/bash +/opt/de_GWD/ui-ddnsCFupdateIP + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/ui-ddnsCF/d' /tmp/now.cron +echo '*/1 * * * * /opt/de_GWD/ui-ddnsCFupdateIP >/dev/null 2>&1' >>/tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron diff --git a/resource/client/ui-script/ui-ddnsCFupdateIP b/resource/client/ui-script/ui-ddnsCFupdateIP new file mode 100755 index 000000000..17eb251d9 --- /dev/null +++ b/resource/client/ui-script/ui-ddnsCFupdateIP @@ -0,0 +1,23 @@ +#!/bin/bash +CFdomain=$(jq -r '.ddns.ddnsCF.cfDomain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +CFzoneID=$(jq -r '.ddns.ddnsCF.CfZoneID' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +CFapikey=$(jq -r '.ddns.ddnsCF.cfAPIkey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +CFemail=$(jq -r '.ddns.ddnsCF.cfEmail' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +wanIP=$(/opt/de_GWD/ui-wanIP_cn) + +CFdomainip=$(dig @127.0.0.1 $CFdomain -4p 5332 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') + +if [[ $wanIP != $CFdomainip ]]; then +CFtopDomain=$(echo $CFdomain | rev | awk -F. '{print $1"."$2}' | rev) + +CFzoneID=$(curl -sX GET "https://api.cloudflare.com/client/v4/zones?name=$CFtopDomain" -H "X-Auth-Email: $CFemail" -H "X-Auth-Key: $CFapikey" -H "Content-Type: application/json" | jq -r '.result[].id') + +CFrecordID=$(curl -sX GET "https://api.cloudflare.com/client/v4/zones/$CFzoneID/dns_records" -H "X-Auth-Email: $CFemail" -H "X-Auth-Key: $CFapikey" -H "Content-Type: application/json" | jq --arg CFdomain "$CFdomain" -r '.result[] | select(.name == $CFdomain).id') + +curl -sX PUT "https://api.cloudflare.com/client/v4/zones/$CFzoneID/dns_records/$CFrecordID" \ + -H "X-Auth-Email: $CFemail" \ + -H "X-Auth-Key: $CFapikey" \ + -H "Content-Type: application/json" \ + --data '{"type":"A","name":"'$CFdomain'","content":"'$wanIP'","ttl":1,"proxied":false}' +fi diff --git a/resource/client/ui-script/ui-hostsCustomize b/resource/client/ui-script/ui-hostsCustomize new file mode 100755 index 000000000..ae338e2e2 --- /dev/null +++ b/resource/client/ui-script/ui-hostsCustomize @@ -0,0 +1,2 @@ +#!/bin/bash +jq -r '.dns.hosts | to_entries[] | [.value, .key] | @tsv' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' diff --git a/resource/client/ui-script/ui-installBitwarden b/resource/client/ui-script/ui-installBitwarden new file mode 100755 index 000000000..39b1f93fc --- /dev/null +++ b/resource/client/ui-script/ui-installBitwarden @@ -0,0 +1,223 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +bitwardenNginxConf (){ +cat << EOF >/etc/nginx/conf.d/bitwarden.conf +server { + listen 8099 ssl http2 fastopen=500 reuseport; + error_page 497 https://\$host:8099\$request_uri; + + include /etc/nginx/conf.d/.HSTS; + + add_header Referrer-Policy "origin" always; + add_header Pragma "no-cache" always; + + include /etc/nginx/conf.d/.ssl_certs; + +location / { + proxy_pass http://127.0.0.1:8098; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; + } + +location /notifications/hub { + proxy_pass http://127.0.0.1:3012; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; +} + +location /notifications/hub/negotiate { + proxy_pass http://127.0.0.1:8098; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; +} +} +EOF +systemctl force-reload nginx +} + + + +bitwardenDockerRun(){ +docker run -d \ + --name bitwarden \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Asia/Shanghai \ + -p 8098:80 \ + -v /opt/bitwarden/:/data/ \ + --dns 1.1.1.1 \ + --restart always \ + --privileged=true \ + vaultwarden/server:latest +} + + + +installBitwarden(){ +mkdir -p /opt/bitwarden + +docker pull vaultwarden/server:latest + +bitwardenDockerRun + +bitwardenNginxConf + +cat << EOF >/etc/logrotate.d/bitwarden +/var/log/bitwarden/*.log { + # 以 bitwarden 用户和群组的身份执行轮换 + su bitwarden bitwarden + # 每天轮换 + daily + # 当尺寸大于 5M 时轮换 + size 5M + # 压缩旧的日志文件 + compress + # 在删除或邮寄到 mail 指令中指定的地址之前,保留 4 个轮换的日志文件 + rotate 4 + # 把当前日志备份并截断 + copytruncate + # 如果日志文件不存在,继续下一个操作 + missingok + # 如果日志文件为空则不进行轮换 + notifempty + # 在轮换的日志文件中添加数字格式的日期 + dateext + # dateext 的日期格式 + dateformat -%Y-%m-%d-%s +} +EOF +jq '.app.bitwarden="installed"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install Bitwarden${cRES}" +} + + + +uninstallBitwarden(){ +docker stop bitwardenrs >/dev/null 2>&1 +docker rm bitwardenrs >/dev/null 2>&1 +docker image ls 2>/dev/null | awk '/bitwardenrs/{print$3}' | while read line; do +docker rmi $line >/dev/null 2>&1 +done + +docker stop bitwarden >/dev/null 2>&1 +docker rm bitwarden >/dev/null 2>&1 +docker image ls 2>/dev/null | awk '/bitwarden/{print$3}' | while read line; do +docker rmi $line >/dev/null 2>&1 +done + +rm -rf /opt/bitwardenrs +rm -rf /opt/bitwarden +rm -rf /etc/nginx/conf.d/bitwardenrs.conf +rm -rf /etc/nginx/conf.d/bitwarden.conf +systemctl force-reload nginx +rm -rf /etc/logrotate.d/bitwarden +jq 'del(.app.bitwardenrs)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +jq 'del(.app.bitwarden)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Uninstall Bitwarden${cRES}" +} + + + +updateBitwarden(){ +docker pull vaultwarden/server:latest + +docker stop bitwarden +docker rm bitwarden + +bitwardenDockerRun + +bitwardenNginxConf + +docker system prune -f + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Update Bitwarden${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} Bitwarden${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install Bitwarden${cRES}" + echo -e "${YELLOW}2. Uninstall Bitwarden${cRES}" + echo -e "${GREEN}0. Update Bitwarden${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installBitwarden + start_menu + ;; + 2) + uninstallBitwarden + start_menu + ;; + 0) + updateBitwarden + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installCER b/resource/client/ui-script/ui-installCER new file mode 100755 index 000000000..ffd5dfa26 --- /dev/null +++ b/resource/client/ui-script/ui-installCER @@ -0,0 +1,226 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +installCER(){ +CFapikey=$(jq -r '.FORWARD.APIkey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +CFemail=$(jq -r '.FORWARD.Email' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +domain=$(jq -r '.FORWARD.domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +topDomain=$(echo $domain | rev | awk -F. '{print $1"."$2}' | rev) + +[[ -f "/etc/nginx/conf.d/80.conf" ]] && sed -i "/server_name/c\server_name $domain;" /etc/nginx/conf.d/80.conf +sed -i "/server_name/c\server_name $domain;" /etc/nginx/conf.d/default.conf +jq --arg serverName "$domain" '.address.serverName = $serverName' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +cat << EOF >/var/www/ssl/update_ocsp_cache +#!/bin/bash +[[ ! -f "/var/www/ssl/intermediate.pem" ]] && wget --show-progress -cqO /var/www/ssl/intermediate.pem https://letsencrypt.org/certs/lets-encrypt-r3-cross-signed.pem +[[ ! -f "/var/www/ssl/root.pem" ]] && wget --show-progress -cqO /var/www/ssl/root.pem https://letsencrypt.org/certs/isrgrootx1.pem + +cat /var/www/ssl/intermediate.pem >/var/www/ssl/bundle.pem +cat /var/www/ssl/root.pem >>/var/www/ssl/bundle.pem + +openssl ocsp -no_nonce \ + -issuer /var/www/ssl/intermediate.pem \ + -cert /var/www/ssl/*.cer \ + -CAfile /var/www/ssl/bundle.pem \ + -VAfile /var/www/ssl/bundle.pem \ + -url http://r3.o.lencr.org \ + -respout /var/www/ssl/ocsp.resp + +systemctl force-reload nginx >/dev/null +EOF +chmod +x /var/www/ssl/update_ocsp_cache + +if [[ $(/var/www/ssl/update_ocsp_cache | awk 'NR==1{print$2}') != "good" ]]; then +rm -rf /var/www/ssl/*.cer +rm -rf /var/www/ssl/*.key +find /var/www/ssl/*.pem | grep -v "dhparam.pem" | xargs -I {} rm -rf {} +cat << EOF >/var/www/ssl/ocsp.resp +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 00 +EOF + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/acme.sh/d' /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron +rm -rf "/root/.acme.sh" + +sed -i '/ssl_trusted_certificate/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling_verify/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling_file/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_early_data/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/proxy_set_header/d' /etc/nginx/conf.d/.ssl_certs +cat << EOF >>/etc/nginx/conf.d/.ssl_certs +ssl_stapling on; +ssl_stapling_verify on; +ssl_stapling_file /var/www/ssl/ocsp.resp; +ssl_trusted_certificate /var/www/ssl/bundle.pem; +ssl_early_data on; +proxy_set_header Early-Data \$ssl_early_data; +EOF + +export CF_Key="$CFapikey" +export CF_Email="$CFemail" + +curl https://get.acme.sh | sh +"/root/.acme.sh"/acme.sh --force --upgrade --auto-upgrade +"/root/.acme.sh"/acme.sh --force --set-default-ca --server letsencrypt +"/root/.acme.sh"/acme.sh --force --issue --dns dns_cf -d $topDomain -d *.$topDomain -k ec-256 --dnssleep 180 +"/root/.acme.sh"/acme.sh --force --installcert -d $topDomain \ + --key-file /var/www/ssl/de_GWD.key \ + --fullchain-file /var/www/ssl/de_GWD.cer \ + --reloadcmd "chmod 644 /var/www/ssl/*.key && systemctl force-reload nginx" \ + --ecc +fi + +/var/www/ssl/update_ocsp_cache + +[[ -d "/opt/de_GWD/vtrui" ]] && systemctl restart vtrui +[[ -d "/opt/de_GWD/vtrui1" ]] && systemctl restart vtrui1 +[[ -d "/opt/de_GWD/coredns" ]] && systemctl restart coredns +[[ -d "/opt/de_GWD/RproxyS" ]] && systemctl restart RproxyS + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Generate & Deploy TLS Certificate${cRES}" +} + + + +resetCER(){ +mkdir -p /var/www/ssl && cd /var/www/ssl + +openssl req -x509 -nodes -days 3650 \ + -subj "/C=CA/ST=QC/O=Company, Inc./CN=localhost.com" \ + -config <(cat /etc/ssl/openssl.cnf \ + <(printf '[SAN]\nsubjectAltName=DNS:localhost')) \ + -newkey rsa:2048 \ + -keyout de_GWD.key \ + -out de_GWD.cer + +rm -rf /var/www/ssl/*.cer +rm -rf /var/www/ssl/*.key +rm -rf /var/www/ssl/*.pem +rm -rf /var/www/ssl/ocsp.resp +cat << EOF >/var/www/ssl/ocsp.resp +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 00 +EOF + +crontab -l 2>/dev/null >/tmp/now.cron +sed -i '/acme.sh/d' /tmp/now.cron +crontab /tmp/now.cron +rm -rf /tmp/now.cron +rm -rf "/root/.acme.sh" + +sed -i '/ssl_trusted_certificate/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling_verify/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_stapling_file/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/ssl_early_data/d' /etc/nginx/conf.d/.ssl_certs +sed -i '/proxy_set_header/d' /etc/nginx/conf.d/.ssl_certs + +systemctl force-reload nginx +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Remove TLS Certificate${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} Domain & Certificate${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Generate TLS Certificate${cRES}" + echo -e "${YELLOW}2. Reset TLS Certificate${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installCER + start_menu + ;; + 2) + resetCER + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installDocker b/resource/client/ui-script/ui-installDocker new file mode 100755 index 000000000..2dbd7126b --- /dev/null +++ b/resource/client/ui-script/ui-installDocker @@ -0,0 +1,83 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' +dockerComposeVer_reserved="1.29.2" + + + +installDocker(){ +curl -sSLo- https://download.docker.com/linux/debian/gpg | gpg --dearmor >/usr/share/keyrings/docker-ce-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-ce-archive-keyring.gpg] https://download.docker.com/linux/debian $(cat /etc/os-release | grep VERSION= | cut -d'(' -f2 | cut -d')' -f1) stable" >/etc/apt/sources.list.d/docker.list + +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^docker-ce$') ]] && aptPKG+=(docker-ce) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^docker-ce-cli$') ]] && aptPKG+=(docker-ce-cli) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^containerd.io$') ]] && aptPKG+=(containerd.io) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) + +if [[ -n $(dpkg -l | awk '{print$2}' | grep '^docker-ce$') ]] && [[ -n $(dpkg -l | awk '{print$2}' | grep '^containerd.io$') ]]; then +mkdir -p /etc/docker/ +systemctl stop docker containerd +cat << EOF >/etc/docker/daemon.json +{ + "iptables": false +} +EOF +systemctl restart docker +fi + +dockerComposeVer=$(curl -sSL "https://api.github.com/repos/docker/compose/releases/latest" | jq -r .tag_name | grep -v '^null$') +[[ -z $dockerComposeVer_reserved ]] && dockerComposeVer=$dockerComposeVer_reserved + +curl -L https://github.com/docker/compose/releases/download/$dockerComposeVer/docker-compose-$(uname -s)-$(uname -m) >/usr/local/bin/docker-compose +chmod +x /usr/local/bin/docker-compose + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install Docker${cRES}" +} + + + +uninstallDocker(){ +rm -rf /etc/apt/sources.list.d/docker.list +apt remove --purge docker-ce docker-ce-cli containerd.io +rm -rf /usr/local/bin/docker-compose + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Uninstall Docker${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} Docker${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install Docker${cRES}" + echo -e "${YELLOW}2. Uninstall Docker${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installDocker + start_menu + ;; + 2) + uninstallDocker + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installFileRun b/resource/client/ui-script/ui-installFileRun new file mode 100755 index 000000000..4a2b67e96 --- /dev/null +++ b/resource/client/ui-script/ui-installFileRun @@ -0,0 +1,190 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' +architecture=$(dpkg --print-architecture) + + + +installFileRun(){ +[[ -z $(dpkg -l | awk '{print$2}' | grep '^mariadb-server$') ]] && echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]\c" && echo -e "\t${YELLOW}Install MariaDB first${cRES}" && exit + +filerunDep + +filerunNginx + +rm -rf /var/www/html/filerun +mkdir -p /var/www/html/filerun +wget --show-progress -cqO /var/www/html/filerun/FileRun.zip https://filerun.com/download-latest +if [[ -n $(unzip -tq /var/www/html/filerun/FileRun.zip | grep "No errors detected in compressed data") ]]; then +unzip /var/www/html/filerun/FileRun.zip -d /var/www/html/filerun >/dev/null +rm -f /var/www/html/filerun/FileRun.zip +chown -R www-data:www-data /var/www/html/filerun + +echo -e "${BLUE}-------------------------------------------------- ${cRES}" +echo -e "${GREEN}FileRun thumbs and previews support${cRES}" +echo +echo -e "${BLUE}FFmpeg: ${YELLOW}/usr/bin/ffmpeg${cRES}" +echo -e "${BLUE}stl-thumb: ${YELLOW}/usr/bin/stl-thumb${cRES}" +echo -e "${BLUE}pngquant: ${YELLOW}/usr/bin/pngquant${cRES}" +echo +echo -e "${BLUE}-------------------------------------------------- ${cRES}" + +else +echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}FileRun${RED} Download Failed${cRES}" +break +fi +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install FileRun${cRES}" +} + + + +filerunDep(){ +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-mysql$') ]] && aptPKG+=(php7.4-mysql) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-mbstring$') ]] && aptPKG+=(php7.4-mbstring) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-curl$') ]] && aptPKG+=(php7.4-curl) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-zip$') ]] && aptPKG+=(php7.4-zip) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-gd$') ]] && aptPKG+=(php7.4-gd) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-ldap$') ]] && aptPKG+=(php7.4-ldap) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-xml$') ]] && aptPKG+=(php7.4-xml) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-json$') ]] && aptPKG+=(php7.4-json) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-opcache$') ]] && aptPKG+=(php7.4-opcache) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-imagick$') ]] && aptPKG+=(php7.4-imagick) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^php7.4-memcached$') ]] && aptPKG+=(php7.4-memcached) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^imagemagick$') ]] && aptPKG+=(imagemagick) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^memcached$') ]] && aptPKG+=(memcached) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^libmemcached-tools$') ]] && aptPKG+=(libmemcached-tools) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^libvips-tools$') ]] && aptPKG+=(libvips-tools) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^pngquant$') ]] && aptPKG+=(pngquant) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^ffmpeg$') ]] && aptPKG+=(ffmpeg) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) +[[ $? -ne 0 ]] && rm -rf /var/lib/apt/lists/lock + +ghREPO="unlimitedbacon/stl-thumb" +ghPackage="_$architecture.deb" +curl -sSL https://api.github.com/repos/${ghREPO}/releases/latest | grep -E 'browser_download_url' | grep 'stl-thumb_' | grep $ghPackage | cut -d '"' -f 4 | wget --show-progress -qi - -O /tmp/stl-thumb.deb +[[ $? -ne 0 ]] && echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}stl-thumb${RED} Download Failed${cRES}" && exit +dpkg -i /tmp/stl-thumb.deb + +case "$architecture" in + amd64) + ioncube_loaders="ioncube_loaders_lin_x86-64.zip" + ;; + arm64) + ioncube_loaders="ioncube_loaders_lin_aarch64.zip" + ;; +esac + +wget --show-progress -cqO /tmp/ioncube_loaders_lin.zip https://downloads.ioncube.com/loader_downloads/$ioncube_loaders +if [[ -n $(unzip -tq /tmp/ioncube_loaders_lin.zip | grep "No errors detected in compressed data") ]]; then +rm -rf /usr/local/ioncube +unzip /tmp/ioncube_loaders_lin.zip -d /usr/local >/dev/null 2>&1 + +echo "zend_extension = /usr/local/ioncube/ioncube_loader_lin_7.4.so" >/etc/php/7.4/mods-available/ioncube.ini +ln -sf /etc/php/7.4/mods-available/ioncube.ini /etc/php/7.4/fpm/conf.d/00-ioncube.ini +ln -sf /etc/php/7.4/mods-available/ioncube.ini /etc/php/7.4/cli/conf.d/00-ioncube.ini +systemctl restart php7.4-fpm +else +echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}ioncube_loader${RED} Download Failed${cRES}" && exit +fi +} + + + +filerunNginx(){ +cat << EOF >/etc/nginx/conf.d/filerun.conf +server { + listen 10501 ssl http2 fastopen=500 reuseport; + root /var/www/html/filerun; + index index.php index.html index.htm; + error_page 497 https://\$host:10501\$request_uri; + + include /etc/nginx/conf.d/.HSTS; + + add_header Referrer-Policy "no-referrer" always; + add_header Pragma "no-cache" always; + + include /etc/nginx/conf.d/.ssl_certs; + +location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_pass unix:/run/php/php7.4-fpm.sock; + fastcgi_index index.php; +} +} +EOF + +systemctl force-reload nginx +} + + + +uninstallFileRun(){ +rm -rf /var/www/html/filerun + +rm -rf /etc/nginx/conf.d/filerun.conf + +sed -i "/zend_extension/d" /etc/php/7.4/fpm/php.ini +sed -i "/zend_extension/d" /etc/php/7.4/cli/php.ini +rm -rf /usr/local/ioncube + +dpkg -r stl-thumb + +apt remove --purge libdrm-dev libosmesa6 libosmesa6-dev libpthread-stubs0-dev libx11-dev libxau-dev libxcb1-dev libxdmcp-dev x11proto-core-dev x11proto-dev xorg-sgml-doctools xtrans-dev mesa-common-dev + +apt remove --purge && apt clean && apt autoclean + +cat << "EOF" >/tmp/filerunRestart +#!/bin/bash +systemctl restart php7.4-fpm +systemctl force-reload nginx +rm -rf /tmp/filerunRestart +EOF +chmod +x /tmp/filerunRestart +tmux new -ds filerunRestart '/tmp/filerunRestart' + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Uninstall FileRun${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} FileRun${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install FileRun${cRES}" + echo -e "${YELLOW}2. Uninstall FileRun${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installFileRun + start_menu + ;; + 2) + uninstallFileRun + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installJellyfin b/resource/client/ui-script/ui-installJellyfin new file mode 100755 index 000000000..69dd1bf39 --- /dev/null +++ b/resource/client/ui-script/ui-installJellyfin @@ -0,0 +1,225 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +jellyfinNginxConf(){ +cat << EOF >/etc/nginx/conf.d/jellyfin.conf +server { + listen 8097 ssl http2 fastopen=500 reuseport; + root /var/www/html; + error_page 497 https://\$host:8097\$request_uri; + + include /etc/nginx/conf.d/.HSTS; + + add_header Referrer-Policy "no-referrer" always; + add_header Pragma "no-cache" always; + + include /etc/nginx/conf.d/.ssl_certs; + +location = / { + return 302 https://\$host:8097/web/; +} + +location / { + proxy_pass http://127.0.0.1:8096; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Forwarded-Host \$http_host; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; +} + +location = /web/ { + proxy_pass http://127.0.0.1:8096/web/index.html; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Forwarded-Host \$http_host; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; +} + +location /socket { + proxy_pass http://127.0.0.1:8096/socket; + proxy_http_version 1.1; + proxy_set_header Accept-Encoding "br, gzip, deflate"; + proxy_set_header Host \$host; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_set_header X-Forwarded-Host \$http_host; + keepalive_requests 100000; + keepalive_timeout 600; + proxy_connect_timeout 600; + proxy_read_timeout 600; + proxy_send_timeout 600; + chunked_transfer_encoding off; + proxy_redirect off; + proxy_store off; + proxy_cache off; + proxy_buffering off; + proxy_buffer_size 8k; +} + +} +EOF +systemctl force-reload nginx >/dev/null +} + + + +jellyfinDockerRun(){ +docker run -d \ + --name jellyfin \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Asia/Shanghai \ + -p 8096:8096 \ + -p 8920:8920 \ + -p 7359:7359/udp \ + -p 1900:1900/udp \ + -v /opt/jellyfin/config:/config \ + -v /opt/jellyfin/cache:/cache \ + --mount type=bind,src=/mnt,dst=/media,bind-propagation=rshared \ + --dns 1.1.1.1 \ + --restart always \ + nyanmisaka/jellyfin:latest +} + + + +installJellyfin(){ +mkdir -p /opt/jellyfin/config +mkdir -p /opt/jellyfin/cache + +docker pull nyanmisaka/jellyfin:latest + +jellyfinDockerRun + +jellyfinNginxConf + +jq '.app.jellyfin="installed"' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install Jellyfin${cRES}" +} + + + +uninstallJellyfin(){ +docker stop jellyfin >/dev/null 2>&1 +docker rm jellyfin >/dev/null 2>&1 +docker image ls 2>/dev/null | awk '/jellyfin/{print$3}' | while read line; do +docker rmi $line >/dev/null 2>&1 +done + +rm -rf /etc/nginx/conf.d/jellyfin.conf +systemctl force-reload nginx >/dev/null + +rm -rf /opt/jellyfin +jq 'del(.app.jellyfin)' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Uninstall Jellyfin${cRES}" +} + + + +updateJellyfin(){ +mkdir -p /opt/jellyfin/config +mkdir -p /opt/jellyfin/cache + +docker pull nyanmisaka/jellyfin:latest + +docker stop jellyfin +docker rm jellyfin + +jellyfinDockerRun + +jellyfinNginxConf + +docker system prune -f + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Update Jellyfin${cRES}" +} + + + +start_menu(){ +[[ -f "/usr/share/keyrings/jellyfin-archive-keyring.gpg" ]] && rm -rf /usr/share/keyrings/jellyfin-archive-keyring.gpg +[[ -f "/etc/apt/sources.list.d/jellyfin.list" ]] && rm -rf /etc/apt/sources.list.d/jellyfin.list + +unset aptPKG +[[ -n $(dpkg -l | awk '{print$2}' | grep '^jellyfin$') ]] && aptPKG+=(jellyfin) +[[ -n $(dpkg -l | awk '{print$2}' | grep '^jellyfin-ffmpeg$') ]] && aptPKG+=(jellyfin-ffmpeg) +[[ -n $(dpkg -l | awk '{print$2}' | grep '^jellyfin-server$') ]] && aptPKG+=(jellyfin-server) +[[ -n $(dpkg -l | awk '{print$2}' | grep '^jellyfin-web$') ]] && aptPKG+=(jellyfin-web) +[[ -n $aptPKG ]] && apt update && apt autoremove --purge $(echo ${aptPKG[@]}) + + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} Jellyfin${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install Jellyfin${cRES}" + echo -e "${YELLOW}2. Uninstall Jellyfin${cRES}" + echo -e "${GREEN}0. Update Jellyfin${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installJellyfin + start_menu + ;; + 2) + uninstallJellyfin + start_menu + ;; + 0) + updateJellyfin + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installMariaDB b/resource/client/ui-script/ui-installMariaDB new file mode 100755 index 000000000..47cf1261a --- /dev/null +++ b/resource/client/ui-script/ui-installMariaDB @@ -0,0 +1,185 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + +installMariaDB(){ + echo -e "${GREEN}================== ${cRES}" + echo -e "${GREEN} Datadase user${cRES}" + echo -e "${GREEN}================== ${cRES}" + read sqluser + + echo -e "${GREEN}================== ${cRES}" + echo -e "${GREEN} Datadase password${cRES}" + echo -e "${GREEN}================== ${cRES}" + read sqlpw + + echo -e "${GREEN}================== ${cRES}" + echo -e "${GREEN} Datadase name${cRES}" + echo -e "${GREEN}================== ${cRES}" + read sqlnm + +apt update && apt install mariadb-server +[[ $? -ne 0 ]] && rm -rf /var/lib/apt/lists/lock + +mysql_secure_installation + +echo -e "${WHITE}Enter current password for root again${cRES}" +read sqlrootpw + +cat << EOF > ~/.my.cnf +[client] +user=root +password=$sqlrootpw +EOF + +mysql -e "create database $sqlnm default charset utf8 collate utf8_general_ci;" +mysql -e "CREATE USER '$sqluser'@'localhost' IDENTIFIED BY '$sqlpw';" +mysql -e "grant all privileges on $sqlnm.* TO '$sqluser'@'localhost';" +rm -rf ~/.my.cnf + +cat << EOF > /etc/mysql/my.cnf +[client] +default-character-set = utf8mb4 +port = 3306 +socket = /run/mysqld/mysqld.sock + +[mysqld] +user = mysql +pid-file = /run/mysqld/mysqld.pid +socket = /run/mysqld/mysqld.sock +port = 3306 +bind-address =127.0.0.1 +basedir = /usr +datadir = /var/lib/mysql +tmpdir = /tmp +lc_messages_dir = /usr/share/mysql +lc_messages = en_US +open_files_limit = 65535 +skip-external-locking + +max_allowed_packet = 32M +max_connections = 300 +table_open_cache = 100 +sort_buffer_size = 4M + +thread_cache_size = 200 +key_buffer_size = 64M +myisam_recover_options = BACKUP +myisam_sort_buffer_size = 64M +bulk_insert_buffer_size = 16M +read_buffer_size = 2M +read_rnd_buffer_size = 1M + +skip-name-resolve +default_storage_engine = InnoDB +innodb_buffer_pool_instances = 1 +innodb_buffer_pool_size = 256M +innodb_open_files = 300 +innodb_io_capacity = 1000 +innodb_read_io_threads = 64 +innodb_write_io_threads = 64 +innodb_log_buffer_size = 32M +innodb_log_file_size = 256M +innodb_file_per_table = 1 +innodb_flush_log_at_trx_commit = 2 +innodb_flush_method = O_DIRECT +innodb_max_dirty_pages_pct = 90 +innodb_large_prefix = on +innodb_file_format = barracuda + +query_cache_type = 1 +query_cache_limit = 512K +query_cache_min_res_unit = 2k +query_cache_size = 64M +tmp_table_size = 32M +max_heap_table_size = 32M + +log_warnings = 2 +slow_query_log = 1 +slow_query_log_file = /var/log/mysql/mariadb.log +long_query_time = 1 +log_slow_verbosity = query_plan +log_bin = /var/log/mysql/mariadb-bin +log_bin_index = /var/log/mysql/mariadb-bin.index +expire_logs_days = 10 +max_binlog_size = 100M + +concurrent_insert = 2 +connect_timeout = 5 +wait_timeout = 600 +character-set-server = utf8mb4 +collation-server = utf8mb4_general_ci +transaction_isolation = READ-COMMITTED +binlog_format = ROW + +[mysqldump] +quick +quote-names +max_allowed_packet = 16M + +[mysql] +no-auto-rehash + +[isamchk] +key_buffer = 16M +EOF +systemctl restart mariadb + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}MariaDB ${GREEN}Installed${cRES}" +} + + + +uninstallMariaDB(){ +systemctl stop mariadb +systemctl disable mariadb +rm -rf /etc/mysql +rm -rf /var/lib/mysql + +apt remove --purge mariadb* +rm -f /var/cache/apt/archives/lock +rm -f /var/lib/apt/lists/lock +rm -f /var/lib/dpkg/lock +rm -f /var/lib/dpkg/lock-frontend +dpkg --configure -a + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}MariaDB ${GREEN}Uninstalled${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} MariaDB${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install MariaDB${cRES}" + echo -e "${YELLOW}2. Uninstall MariaDB${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installMariaDB + start_menu + ;; + 2) + uninstallMariaDB + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installNFS b/resource/client/ui-script/ui-installNFS new file mode 100755 index 000000000..65e364e17 --- /dev/null +++ b/resource/client/ui-script/ui-installNFS @@ -0,0 +1,71 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + +installNFSsupport(){ +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install NFS${cRES}\r\c" +unset aptPKG +[[ -z $(dpkg -l | awk '{print$2}' | grep '^autofs$') ]] && aptPKG+=(autofs) +[[ -z $(dpkg -l | awk '{print$2}' | grep '^nfs-common$') ]] && aptPKG+=(nfs-common) +[[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) + +rm -rf '/etc/auto.master.d' +sed -i '/+auto.master/,$d' /etc/auto.master +cat << EOF >>/etc/auto.master ++auto.master +/net -hosts --timeout=60 +/media/misc /etc/autofs/auto.misc --timeout=5 +/media/net /etc/autofs/auto.net --timeout=60 +/- /etc/auto.nfs +EOF +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install NFS${cRES}" +} + + + +uninstallNFSsupport(){ +apt remove --purge autofs nfs-common + +rm -rf /etc/auto.master.d/nfs.autofs + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}NFS ${GREEN}Uninstalled${cRES}" +} + + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} NFS support${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install NFS support${cRES}" + echo -e "${YELLOW}2. Uninstall NFS support${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installNFSsupport + start_menu + ;; + 2) + uninstallNFSsupport + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu + diff --git a/resource/client/ui-script/ui-installWG b/resource/client/ui-script/ui-installWG new file mode 100755 index 000000000..4c549255a --- /dev/null +++ b/resource/client/ui-script/ui-installWG @@ -0,0 +1,57 @@ +#!/bin/bash +clear +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +installWGcore(){ +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Install Wireguard${cRES}\r\c" +uname -r 2>&1 | grep -o '[0-9.]*' | head -n 1 >/tmp/kernelVer +echo "5.6" >>/tmp/kernelVer + +if [[ $(cat /tmp/kernelVer | sort -rV | head -n 1) = "5.6" ]]; then + echo -e "${WHITE}[ ${YELLOW}! ${WHITE}]\c" && echo -e "\t${YELLOW}Update kernel first ! ${cRES}" +else + unset aptPKG + [[ -z $(dpkg -l | awk '{print$2}' | grep '^wireguard-tools$') ]] && aptPKG+=(wireguard-tools) + [[ -n $aptPKG ]] && apt update && apt install $(echo ${aptPKG[@]}) + + if [[ -z $(jq -r '.wireguard.server.sprivatekey' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then + /opt/de_GWD/ui-WGgenSkey + fi +fi + +rm -rf /tmp/kernelVer +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Install Wireguard${cRES}" +} + + +start_menu(){ + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN} Wireguard${cRES}" + echo -e "${GREEN}=============================== ${cRES}" + echo -e "${GREEN}1. Install Wireguard${cRES}" + echo "" + read -p "Select:" num + case "$num" in + 1) + installWGcore + start_menu + ;; + *) + clear + echo -e "${RED}Wrong number${cRES}" + sleep 1s + start_menu + ;; + esac +} + +start_menu \ No newline at end of file diff --git a/resource/client/ui-script/ui-installZ b/resource/client/ui-script/ui-installZ new file mode 100755 index 000000000..bf1ed0909 --- /dev/null +++ b/resource/client/ui-script/ui-installZ @@ -0,0 +1,10 @@ +#!/bin/bash +rm -rf /opt/de_GWD/update + +kill $(ps -e | grep 'ttyd' | awk '{print$1}') >/dev/null 2>&1 + +[[ -n $(cat /etc/resolv.conf | grep -v '127.0.0.1') ]] && resolvconf -u + +ps -aux | grep 'ui-install' | sed '/grep/d' | awk '{print$2}' | while read line; do +kill $line >/dev/null 2>&1 +done diff --git a/resource/client/ui-script/ui-markThis b/resource/client/ui-script/ui-markThis new file mode 100755 index 000000000..dee973efe --- /dev/null +++ b/resource/client/ui-script/ui-markThis @@ -0,0 +1,10 @@ +#!/bin/bash +markName=$(jq -r '.address.alias' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +sed -i "//c\<title>$markName \ 寒月" /var/www/html/index.php +sed -i "//c\<title>$markName \ 中转" /var/www/html/forward.php +sed -i "//c\<title>$markName \ DDNS & Wireguard" /var/www/html/ddns.php +sed -i "//c\<title>$markName \ 应用" /var/www/html/app.php +sed -i "//c\<title>$markName \ 黑白名单" /var/www/html/listBW.php +sed -i "//c\<title>$markName \ 节点管理" /var/www/html/nodes.php +sed -i "//c\<title>$markName \ 更新" /var/www/html/update.php diff --git a/resource/client/ui-script/ui-pingTCP b/resource/client/ui-script/ui-pingTCP new file mode 100755 index 000000000..3c08d730a --- /dev/null +++ b/resource/client/ui-script/ui-pingTCP @@ -0,0 +1,3 @@ +#!/bin/bash +pingTCP=$(jq -r --argjson domainNUM "$1" '.v2node[$domainNUM].domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +echo "$(curl -o /dev/null -m 5 -kIsw '%{time_connect}\n' https://$pingTCP) * 1000" | bc | awk '{printf ("%.0f\n",$1)}' diff --git a/resource/client/ui-script/ui-pingTCPDOH1 b/resource/client/ui-script/ui-pingTCPDOH1 new file mode 100755 index 000000000..36e2e5834 --- /dev/null +++ b/resource/client/ui-script/ui-pingTCPDOH1 @@ -0,0 +1,3 @@ +#!/bin/bash +pingTCPDOH=$(jq -r '.dns.doh[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | awk NR==1 | cut -d/ -f1) +echo "$(curl -o /dev/null -m 5 -kIsw '%{time_connect}\n' https://$pingTCPDOH) * 1000" | bc | awk '{printf ("%.0f\n",$1)}' diff --git a/resource/client/ui-script/ui-pingTCPDOH2 b/resource/client/ui-script/ui-pingTCPDOH2 new file mode 100755 index 000000000..d72a0019c --- /dev/null +++ b/resource/client/ui-script/ui-pingTCPDOH2 @@ -0,0 +1,3 @@ +#!/bin/bash +pingTCPDOH=$(jq -r '.dns.doh[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | awk NR==2 | cut -d/ -f1) +echo "$(curl -o /dev/null -m 5 -kIsw '%{time_connect}\n' https://$pingTCPDOH) * 1000" | bc | awk '{printf ("%.0f\n",$1)}' diff --git a/resource/client/ui-script/ui-pingTCPDoG b/resource/client/ui-script/ui-pingTCPDoG new file mode 100755 index 000000000..11974c6b4 --- /dev/null +++ b/resource/client/ui-script/ui-pingTCPDoG @@ -0,0 +1,3 @@ +#!/bin/bash +pingTCPDoG=$(jq -r '.dns.dog' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | cut -d/ -f1) +echo "$(curl -o /dev/null -m 5 -kIsw '%{time_connect}\n' https://$pingTCPDoG) * 1000" | bc | awk '{printf ("%.0f\n",$1)}' diff --git a/resource/client/ui-script/ui-proxyRestart b/resource/client/ui-script/ui-proxyRestart new file mode 100755 index 000000000..2edca8059 --- /dev/null +++ b/resource/client/ui-script/ui-proxyRestart @@ -0,0 +1,33 @@ +#!/bin/bash +sed -i '/PIHOLE_DNS_.*/d' /etc/pihole/setupVars.conf +cat << EOF >>/etc/pihole/setupVars.conf +PIHOLE_DNS_1=127.0.0.1#5341 +EOF + +sed -i '/server=/d' /etc/dnsmasq.d/01-pihole.conf +cat << EOF >>/etc/dnsmasq.d/01-pihole.conf +server=127.0.0.1#5341 +EOF +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 +systemctl restart pihole-FTL + +>/etc/resolvconf/resolv.conf.d/head +>/etc/resolvconf/resolv.conf.d/original +>/etc/resolvconf/resolv.conf.d/tail +rm -rf /etc/resolv.conf +rm -rf /run/resolvconf/interface +cat << EOF >/etc/resolvconf/resolv.conf.d/base +nameserver 127.0.0.1 +EOF +if [[ -f "/etc/resolvconf/run/resolv.conf" ]]; then +ln -sf /etc/resolvconf/run/resolv.conf /etc/resolv.conf +elif [[ -f "/run/resolvconf/resolv.conf" ]]; then +ln -sf /run/resolvconf/resolv.conf /etc/resolv.conf +fi +sed -i '/dns-nameservers /d' /etc/network/interfaces +resolvconf -u + +systemctl restart samrtdns +systemctl restart mosdns +systemctl restart vtrui +systemctl restart nftables diff --git a/resource/client/ui-script/ui-proxyStop b/resource/client/ui-script/ui-proxyStop new file mode 100755 index 000000000..19e2dcb23 --- /dev/null +++ b/resource/client/ui-script/ui-proxyStop @@ -0,0 +1,34 @@ +#!/bin/bash +sed -i '/PIHOLE_DNS_.*/d' /etc/pihole/setupVars.conf +cat << EOF >>/etc/pihole/setupVars.conf +PIHOLE_DNS_1=127.0.0.1#5331 +EOF + +sed -i '/server=/d' /etc/dnsmasq.d/01-pihole.conf +cat << EOF >>/etc/dnsmasq.d/01-pihole.conf +server=127.0.0.1#5331 +EOF +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 +systemctl restart pihole-FTL + +>/etc/resolvconf/resolv.conf.d/head +>/etc/resolvconf/resolv.conf.d/original +>/etc/resolvconf/resolv.conf.d/tail +rm -rf /etc/resolv.conf +rm -rf /run/resolvconf/interface +cat << EOF >/etc/resolvconf/resolv.conf.d/base +nameserver 127.0.0.1 +EOF +if [[ -f "/etc/resolvconf/run/resolv.conf" ]]; then +ln -sf /etc/resolvconf/run/resolv.conf /etc/resolv.conf +elif [[ -f "/run/resolvconf/resolv.conf" ]]; then +ln -sf /run/resolvconf/resolv.conf /etc/resolv.conf +fi +sed -i '/dns-nameservers /d' /etc/network/interfaces +resolvconf -u + +systemctl stop nftables +ip rule del table 220 >/dev/null 2>&1 +ip route flush table 220 >/dev/null 2>&1 +ip route flush cache >/dev/null 2>&1 +ip route del local default dev lo table 220 >/dev/null 2>&1 diff --git a/resource/client/ui-script/ui-reboot b/resource/client/ui-script/ui-reboot new file mode 100755 index 000000000..628e712f1 --- /dev/null +++ b/resource/client/ui-script/ui-reboot @@ -0,0 +1,33 @@ +#!/bin/bash +#!/bin/bash +PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' + +ethernetnum=$(ip link show | grep -v "lo" | awk '{print$2;exit}' | cut -d':' -f1 | cut -d'@' -f1) +gatewayaddr=$(jq -r '.address.upstreamIP' /opt/de_GWD/0conf | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') +localAddrCIDR=$(jq -r '.address.localIP' /opt/de_GWD/0conf | grep -v '^null$') +localAddr=$(echo $localAddrCIDR | cut -d / -f1) +netmask=$(echo $localAddrCIDR | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}//g') + +[[ -z $netmask ]] && netmask="/24" && localAddrCIDR="$localAddr$netmask" + +if [[ -n $localAddr ]] && [[ -n $gatewayaddr ]]; then +cat << EOF >/etc/network/interfaces +source /etc/network/interfaces.d/* + +auto lo +iface lo inet loopback + +auto $ethernetnum +iface $ethernetnum inet static + address $localAddrCIDR + gateway $gatewayaddr +EOF + +sed -i "/IPV4_ADDRESS=/c\IPV4_ADDRESS=$localAddrCIDR" /etc/pihole/setupVars.conf +fi + +jq --arg localAddrCIDR "$localAddrCIDR" '.address.localIP=$localAddrCIDR' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf +chmod 666 /opt/de_GWD/0conf + +sleep 1 +reboot diff --git a/resource/client/ui-script/ui-restore b/resource/client/ui-script/ui-restore new file mode 100755 index 000000000..f2d72d45b --- /dev/null +++ b/resource/client/ui-script/ui-restore @@ -0,0 +1,44 @@ +#!/bin/bash +if [[ $(du -sk /var/www/html/restore/de_GWD_bak 2>/dev/null | awk '{print$1}') -gt 1 ]]; then +mv -f /var/www/html/restore/de_GWD_bak /opt/de_GWD/0conf + +if [[ -n $(jq -r '.address.alias' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then + /opt/de_GWD/ui-markThis +fi + +/opt/de_GWD/ui-NodeOne + +if [[ $(jq -r '.address.dhcp' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-DHCPon +fi + +if [[ $(jq -r '.v2nodeDIV.nodeSM.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeSM >/dev/null 2>&1 +fi + +if [[ $(jq -r '.v2nodeDIV.nodeCU.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeCU >/dev/null 2>&1 +fi + +if [[ $(jq -r '.v2nodeDIV.nodeDT.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]]; then + /opt/de_GWD/ui-NodeDT >/dev/null 2>&1 +fi + +if [[ $(jq -r '.FORWARD.FWD1.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-FWD1save >/dev/null 2>&1 +fi + +if [[ $(jq -r '.FORWARD.Rproxy.client.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-RproxyCsave >/dev/null 2>&1 +fi + +if [[ $(jq -r '.FORWARD.Rproxy.server.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-RproxySsave >/dev/null 2>&1 +fi + +/opt/de_GWD/ui_4h + +systemctl restart nftables +systemctl restart mosdns +systemctl restart vtrui +fi diff --git a/resource/client/ui-script/ui-restoreBitwarden b/resource/client/ui-script/ui-restoreBitwarden new file mode 100755 index 000000000..ab61f393f --- /dev/null +++ b/resource/client/ui-script/ui-restoreBitwarden @@ -0,0 +1,22 @@ +#!/bin/bash +docker stop bitwarden + +if [[ -n $(unzip -tq /var/www/html/restore/Bitwarden_bak.zip | grep "No errors detected in compressed data") ]]; then +rm -rf /tmp/opt +unzip /var/www/html/restore/Bitwarden_bak.zip -d /tmp + +rm -rf /opt/bitwarden +mkdir -p /opt/bitwarden + +if [[ -d "/tmp/opt/bitwardenrs" ]]; then +mv -f /tmp/opt/bitwardenrs/* /opt/bitwarden +else +mv -f /tmp/opt/bitwarden/* /opt/bitwarden +fi + +fi + +docker restart bitwarden + +rm -rf /tmp/opt +rm -rf /var/www/html/restore/Bitwarden_bak.zip diff --git a/resource/client/ui-script/ui-restoreJellyfin b/resource/client/ui-script/ui-restoreJellyfin new file mode 100755 index 000000000..2e94e00ef --- /dev/null +++ b/resource/client/ui-script/ui-restoreJellyfin @@ -0,0 +1,16 @@ +#!/bin/bash +docker stop jellyfin + +if [[ -n $(unzip -tq /var/www/html/restore/Jellyfin_bak.zip | grep "No errors detected in compressed data") ]]; then +rm -rf /tmp/opt +unzip /var/www/html/restore/Jellyfin_bak.zip -d /tmp + +rm -rf /opt/jellyfin +mkdir -p /opt/jellyfin +mv -f /tmp/opt/jellyfin/* /opt/jellyfin +fi + +docker restart jellyfin + +rm -rf /tmp/opt +rm -rf /var/www/html/restore/Jellyfin_bak.zip diff --git a/resource/client/ui-script/ui-smartDNS b/resource/client/ui-script/ui-smartDNS new file mode 100755 index 000000000..f862a3430 --- /dev/null +++ b/resource/client/ui-script/ui-smartDNS @@ -0,0 +1,157 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}SmartDNS action${cRES}\r\c" +doh1=$(jq -r '.dns.doh[0]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +doh2=$(jq -r '.dns.doh[1]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +DoG=$(jq -r '.dns.dog' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') + +touch /opt/de_GWD/coredns/corefile +if [[ -n $DoG ]]; then +DoGcDomain=$(echo $DoG | cut -d: -f1) +DoGcIP=$(dig @127.0.0.1 $DoGcDomain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +DoGcPort=$(echo $DoG | cut -d: -f2 | grep '^[[:digit:]]*$') +fi + +if [[ -n $DoGcIP ]]; then +sed -i '/DoGc_START/,/DoGc_END/d' /opt/de_GWD/coredns/corefile +tac /opt/de_GWD/coredns/corefile | awk 'NF>0{x=1}x' | tac | sponge /opt/de_GWD/coredns/corefile >/dev/null 2>&1 +cat << EOF >>/opt/de_GWD/coredns/corefile +# DoGc_START +.:5333 { +bind 127.0.0.1 +grpc . $DoGcIP:$DoGcPort { + tls_servername $DoGcDomain +} +template ANY AAAA { + rcode NXDOMAIN +} +reload 6s 3s +} +# DoGc_END +EOF + +systemctl enable coredns >/dev/null 2>&1 +systemctl restart coredns +else +sed -i '/DoGc_START/,/DoGc_END/d' /opt/de_GWD/coredns/corefile + if [[ $(cat /opt/de_GWD/coredns/corefile | wc -l) -le 5 ]]; then + systemctl disable coredns >/dev/null 2>&1 + systemctl stop coredns + else + systemctl restart coredns + fi +fi + +if [[ $(jq -r '.FORWARD.DoGs.status' /opt/de_GWD/0conf 2>/dev/null) = "on" ]];then + /opt/de_GWD/ui-DoGsSave >/dev/null 2>&1 +fi + +if [[ -n $doh1 ]]; then +doh1Domain=$(echo $doh1 | cut -d/ -f1 | cut -d: -f1) +doh1IP=$(dig @127.0.0.1 $doh1Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +doh1Port=$(echo $doh1 | cut -d/ -f1 | cut -d: -f2 | grep '^[[:digit:]]*$') +doh1Path=$(echo $doh1 | cut -d/ -f2) + +if [[ -z $doh1Port ]]; then + doh1Str="$doh1IP/$doh1Path" +else + doh1Str="$doh1IP:$doh1Port/$doh1Path" +fi +fi + +if [[ -n $doh2 ]]; then +doh2Domain=$(echo $doh2 | cut -d/ -f1 | cut -d: -f1) +doh2IP=$(dig @127.0.0.1 $doh2Domain -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | grep -v "127.0.0.1" | xargs -n 1 | awk NR==1) +doh2Port=$(echo $doh2 | cut -d/ -f1 | cut -d: -f2 | grep '^[[:digit:]]*$') +doh2Path=$(echo $doh2 | cut -d/ -f2) + +if [[ -z $doh2Port ]]; then + doh2Str="$doh2IP/$doh2Path" +else + doh2Str="$doh2IP:$doh2Port/$doh2Path" +fi +fi + +cat << EOF >/opt/de_GWD/smartdns/smartdns.conf +server-name smartdns + +bind 127.0.0.1:5331 +bind-tcp 127.0.0.1:5331 + +bind 127.0.0.1:5332 -group DNS_global -no-speed-check -no-cache +bind-tcp 127.0.0.1:5332 -group DNS_global -no-speed-check -no-cache + +speed-check-mode tcp:443,ping,tcp:80 +response-mode first-ping +force-AAAA-SOA yes +dualstack-ip-selection no +cache-size 32768 +cache-persist yes +cache-file /tmp/smartdns +cache-checkpoint-time 28800 +prefetch-domain yes +serve-expired-prefetch-time 21600 +rr-ttl 600 +rr-ttl-min 60 +rr-ttl-max 3600 +local-ttl 60 +serve-expired yes +serve-expired-ttl 3600 +serve-expired-reply-ttl 3 + +dnsmasq-lease-file /etc/pihole/dhcp.leases + +EOF + +if [[ -z $(jq -r '.dns.china' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then + jq --arg dnsChina "114.114.114.114 114.114.115.115 119.29.29.29 119.28.28.28 180.76.76.76 223.5.5.5 223.6.6.6" '.dns.china=$dnsChina' /opt/de_GWD/0conf | sponge /opt/de_GWD/0conf + chmod 666 /opt/de_GWD/0conf +fi + +for dnsChina in $(jq -r '.dns.china' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$'); do + echo "server $dnsChina" >>/opt/de_GWD/smartdns/smartdns.conf +done + + +if [[ -n $doh1IP ]]; then +echo "server-https https://$doh1Str -host-name $doh1Domain -no-check-certificate -group DNS_global -exclude-default-group" >>/opt/de_GWD/smartdns/smartdns.conf +fi + +if [[ -n $doh2IP ]]; then +echo "server-https https://$doh2Str -host-name $doh2Domain -no-check-certificate -group DNS_global -exclude-default-group" >>/opt/de_GWD/smartdns/smartdns.conf +fi + +if [[ -n $DoGcIP ]]; then +echo "server-tcp 127.0.0.1:5333" >>/opt/de_GWD/smartdns/smartdns.conf +fi + +systemctl restart smartdns + +if [[ -n $DoGcIP ]] || [[ -n $doh1IP ]] || [[ -n $doh2IP ]]; then +echo $DoGcIP $doh1IP $doh2IP | xargs -n1 | sort | uniq | sed 's/$/,/g' >/opt/de_GWD/nftables/IP_GlobalDNS +nft flush set ip de_GWD GlobalDNS +cat << EOF >/opt/de_GWD/nftables/SET_GlobalDNS.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set GlobalDNS { + type ipv4_addr + flags interval + auto-merge + elements = { $(cat /opt/de_GWD/nftables/IP_GlobalDNS) } + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_GlobalDNS.nft +/opt/de_GWD/nftables/SET_GlobalDNS.nft +fi +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}SmartDNS action${cRES}" diff --git a/resource/client/ui-script/ui-speedT b/resource/client/ui-script/ui-speedT new file mode 100755 index 000000000..67c8d2562 --- /dev/null +++ b/resource/client/ui-script/ui-speedT @@ -0,0 +1,3 @@ +#!/bin/bash +speedT=$(jq -r --argjson domainNUM "$1" '.v2node[$domainNUM].domain' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') +wget -O /dev/null https://$speedT/spt 2>&1 | sed '$d' | awk 'END{print$3}' | sed 's/(//' diff --git a/resource/client/ui-script/ui-submitADList b/resource/client/ui-script/ui-submitADList new file mode 100755 index 000000000..9748f3b58 --- /dev/null +++ b/resource/client/ui-script/ui-submitADList @@ -0,0 +1,34 @@ +#!/bin/bash +rm -rf /etc/pihole/gravity_*.db +rm -rf /etc/pihole/list.* +[[ ! -f "/etc/pihole/gravity.db" ]] && pihole -g +sqlite3 /etc/pihole/gravity.db "DELETE FROM adlist" +sqlite3 /etc/pihole/gravity.db "DELETE FROM domainlist where type=0" +sqlite3 /etc/pihole/gravity.db "DELETE FROM domainlist where type=1" +sqlite3 /etc/pihole/gravity.db "DELETE FROM domainlist where type=2" +sqlite3 /etc/pihole/gravity.db "DELETE FROM domainlist where type=3" + + +jq -r '.dns.adlists[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | while read line; do + pihole -a adlist add "$line" "adlists by de_GWD" +done + +jq -r '.dns.adWlist[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | while read line; do + pihole -w "$line" --comment "Whitelist by de_GWD" +done + +jq -r '.dns.adBlist[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$' | while read line; do + pihole -b "$line" --comment "Blacklist by de_GWD" +done + +for line in $(jq -r '.dns.adWregex[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$'); do + pihole --white-regex $line --comment "Regex whitelist by de_GWD" +done + +for line in $(jq -r '.dns.adBregex[]' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$'); do + pihole --regex "$line" --comment "Regex blacklist by de_GWD" +done + + +pihole -g +[[ $1 = "r" ]] && pihole restartdns diff --git a/resource/client/ui-script/ui-submitListBW b/resource/client/ui-script/ui-submitListBW new file mode 100755 index 000000000..0d22745bb --- /dev/null +++ b/resource/client/ui-script/ui-submitListBW @@ -0,0 +1,71 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Collect Black and white list${cRES}\r\c" + +>/opt/de_GWD/mosdns/domains_listB +>/opt/de_GWD/nftables/IP_listB +jq -r '.dns.listB[]' /opt/de_GWD/0conf 2>/dev/null | sort | uniq | xargs -n 1 | sed '/^\s*$/d' | while read listB; do + echo $listB >>/opt/de_GWD/mosdns/domains_listB + dig @127.0.0.1 $listB -4p 5332 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | xargs -n1 >>/opt/de_GWD/nftables/IP_listB +done + + +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_listB +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_listB +[[ -n $(cat /opt/de_GWD/nftables/IP_listB 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listB_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listB) }" +nft flush set ip de_GWD listB +cat << EOF >/opt/de_GWD/nftables/SET_listB.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listB { + type ipv4_addr + flags interval + auto-merge + $IP_listB_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listB.nft +/opt/de_GWD/nftables/SET_listB.nft + + + + +>/opt/de_GWD/mosdns/domains_listW +>/opt/de_GWD/nftables/IP_listW +jq -r '.dns.listW[]' /opt/de_GWD/0conf 2>/dev/null | sort | uniq | xargs -n 1 | sed '/^\s*$/d' | while read listW; do + echo $listW >>/opt/de_GWD/mosdns/domains_listW + dig @127.0.0.1 $listW -4p 5331 +short | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | xargs -n1 >>/opt/de_GWD/nftables/IP_listW +done + + +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_listW +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_listW +[[ -n $(cat /opt/de_GWD/nftables/IP_listW 2>&1 | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') ]] && IP_listW_elements="elements = { $(cat /opt/de_GWD/nftables/IP_listW) }" +nft flush set ip de_GWD listW +cat << EOF >/opt/de_GWD/nftables/SET_listW.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set listW { + type ipv4_addr + flags interval + auto-merge + $IP_listW_elements + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_listW.nft +/opt/de_GWD/nftables/SET_listW.nft + +/opt/de_GWD/ui-submitListBWsm + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Collect Black and white list${cRES}" diff --git a/resource/client/ui-script/ui-submitListBWsm b/resource/client/ui-script/ui-submitListBWsm new file mode 100755 index 000000000..44677f973 --- /dev/null +++ b/resource/client/ui-script/ui-submitListBWsm @@ -0,0 +1,15 @@ +#!/bin/bash +jq -r '.dns.listB[]' /opt/de_GWD/0conf 2>/dev/null | sort | uniq | xargs -n 1 | sed '/^\s*$/d' >/opt/de_GWD/mosdns/domains_listB +jq -r '.dns.listW[]' /opt/de_GWD/0conf 2>/dev/null | sort | uniq | xargs -n 1 | sed '/^\s*$/d' >/opt/de_GWD/mosdns/domains_listW + + + +if [[ -z $(jq -r '.v2nodeDIV.nodeSM.apple' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then +cat /opt/de_GWD/.repo/Domains.apple.txt >>/opt/de_GWD/mosdns/domains_listW +else +cat /opt/de_GWD/.repo/Domains.apple.txt >>/opt/de_GWD/mosdns/domains_listB +fi + +if [[ -z $(jq -r '.v2nodeDIV.nodeSM.steam' /opt/de_GWD/0conf 2>/dev/null | grep -v '^null$') ]]; then +cat /opt/de_GWD/.repo/Domains.games.txt >>/opt/de_GWD/mosdns/domains_listW +fi diff --git a/resource/client/ui-script/ui-updateSave b/resource/client/ui-script/ui-updateSave new file mode 100755 index 000000000..bbfb754da --- /dev/null +++ b/resource/client/ui-script/ui-updateSave @@ -0,0 +1,27 @@ +#!/bin/bash +chmod +x /opt/de_GWD/update +if [[ $(du -sk /opt/de_GWD/update 2>/dev/null | awk '{print$1}') -le 1 ]]; then +updateCMDaddr=$(jq -r '.update.updateCMD' /opt/de_GWD/0conf 2>/dev/null | grep -oP "https://\K[^']+" | sed s'/.$//') +systemctl stop nftables + +[[ -n "$(ps -e | grep 'pihole-FTL' )" ]] && systemctl stop pihole-FTL +kill -9 $(ps -e | grep 'pihole' | awk '{print$1}') >/dev/null 2>&1 + +rm -rf /etc/resolv.conf +cat << EOF >/etc/resolv.conf +nameserver 119.29.29.29 +nameserver 180.76.76.76 +nameserver 114.114.114.114 +nameserver 223.5.5.5 +EOF + +wget -cqO /opt/de_GWD/update $updateCMDaddr +fi + +updatePort=$(jq -r '.update.updatePort' /opt/de_GWD/0conf) + +kill $(ps -e | grep 'ttyd' | awk '{print$1}') >/dev/null 2>&1 +tmux kill-session -t updateGWD >/dev/null 2>&1 +sed -i "/ExecStart=/c\ExecStart=/usr/bin/tmux new -ds 'updateGWD' /usr/bin/ttyd -p $updatePort -o /opt/de_GWD/update" /etc/systemd/system/updateGWD.service +systemctl daemon-reload >/dev/null + diff --git a/resource/client/ui-script/ui-wanIP_cn b/resource/client/ui-script/ui-wanIP_cn new file mode 100755 index 000000000..6bbe010f3 --- /dev/null +++ b/resource/client/ui-script/ui-wanIP_cn @@ -0,0 +1,18 @@ +#!/bin/bash +unset publicIPurls +publicIPurls+=(http://members.3322.org/dyndns/getip) +publicIPurls+=(http://ip.3322.net) +publicIPurls+=(https://v4.yinghualuo.cn/bejson) +publicIPurls+=(http://myip.ipip.net) +publicIPurls+=(http://cip.cc) + +for (( i=0; i<10; ++i)); do + wanIP=$(curl -ksLm 1 ${publicIPurls[$RANDOM % ${#publicIPurls[@]}]} 2>/dev/null) + [[ -n $(echo $wanIP | grep '移动') ]] && wanIP="" + wanIP=$(echo $wanIP | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | xargs -n1 | head -n1) + [[ -n $wanIP ]] && [[ -z $(nft get element ip de_GWD CHNROUTE { $wanIP } | grep 'Error:') ]] && break + wanIP="" + sleep 1 +done + +echo $wanIP diff --git a/resource/client/ui-script/ui-wanIP_global b/resource/client/ui-script/ui-wanIP_global new file mode 100755 index 000000000..1cd2ecc57 --- /dev/null +++ b/resource/client/ui-script/ui-wanIP_global @@ -0,0 +1,14 @@ +#!/bin/bash +unset publicIPurls +publicIPurls+=(http://ifconfig.me) +publicIPurls+=(http://whatismyip.akamai.com) +publicIPurls+=(http://ip.sb) +publicIPurls+=(http://icanhazip.com) + +for (( i=0; i<10; ++i)); do + wanIP=$(curl -4sSLm 1 ${publicIPurls[$RANDOM % ${#publicIPurls[@]}]} 2>/dev/null | grep -Po '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | xargs -n1 | awk NR==1 | grep -v '127.0.0.1') + [[ -n $wanIP ]] && break + sleep 1 +done + +echo $wanIP diff --git a/resource/client/ui-script/ui_2h b/resource/client/ui-script/ui_2h new file mode 100755 index 000000000..42f6ae5ad --- /dev/null +++ b/resource/client/ui-script/ui_2h @@ -0,0 +1,25 @@ +#!/bin/bash +rm -rf /opt/de_GWD/update +rm -rf /opt/de_GWD/__MACOSX +rm -rf ~/client* +rm -rf ~/wget-log* +rm -rf /var/log/*1* +rm -rf /var/log/*2* +rm -rf /var/log/*.gz +rm -rf /var/log/auth.log +rm -rf /var/log/lighttpd* +rm -rf /var/www/html/log.log +rm -rf /var/www/html/restore/* +rm -rf /var/www/html/__MACOSX +rm -rf /tmp/systemd-private-* +rm -rf /tmp/tmp.* + + + +sed -i '/^\s*$/d' /opt/de_GWD/0conf +if [[ -n $(cat /opt/de_GWD/0conf) ]]; then + cp -f /opt/de_GWD/0conf /opt/de_GWD/0conf_bak +elif [[ -z $(cat /opt/de_GWD/0conf) ]]; then + cp -f /opt/de_GWD/0conf_bak /opt/de_GWD/0conf + chmod 666 /opt/de_GWD/0conf +fi diff --git a/resource/client/ui-script/ui_4am b/resource/client/ui-script/ui_4am new file mode 100755 index 000000000..f3ec07354 --- /dev/null +++ b/resource/client/ui-script/ui_4am @@ -0,0 +1,154 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +/opt/de_GWD/tcpTime + +serverConnect1=$(curl -Is -m 5 google.com | grep 'HTTP') +serverConnect2=$(curl -Is -m 5 youtube.com | grep 'HTTP') +[[ -z $serverConnect1 ]] && [[ -z $serverConnect2 ]] && exit + +[[ $1 = "u" ]] && service cron stop + +echo -e "${WHITE}[...]\c" && echo -e "\t${WHITE}Update CHN Domain & IP rules${cRES}\r\c" +checkSum(){ +sha256sumL=$(sha256sum $1 2>/dev/null | awk '{print$1}') +if [[ $sha256sumL = $2 ]]; then + echo "true" +elif [[ $sha256sumL != $2 ]]; then + echo "false" +fi +} + +geosite_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat.sha256sum | awk '{print$1}') +geoip_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip.dat.sha256sum | awk '{print$1}') +IPchnroute_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/chnroute/main/IPchnroute.sha256sum) +DomainsChn_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.chn.txt.sha256sum) +DomainsApple_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.apple.txt.sha256sum) +DomainsGames_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.games.txt.sha256sum) +bogusNxdomain_sha256sum=$(curl -sSLo- https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/99-bogus-nxdomain.china.conf.sha256sum) + +if [[ $(checkSum /opt/de_GWD/.repo/geosite.dat $geosite_sha256sum) = "false" ]]; then +rm -rf /tmp/geosite.dat +wget --show-progress -cqO /tmp/geosite.dat https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat + if [[ $(checkSum /tmp/geosite.dat $geosite_sha256sum) = "true" ]]; then + mv -f /tmp/geosite.dat /opt/de_GWD/.repo/geosite.dat + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}geosite.dat${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /opt/de_GWD/.repo/geoip.dat $geoip_sha256sum) = "false" ]]; then +rm -rf /tmp/geoip.dat +wget --show-progress -cqO /tmp/geoip.dat https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip.dat + if [[ $(checkSum /tmp/geoip.dat $geoip_sha256sum) = "true" ]]; then + mv -f /tmp/geoip.dat /opt/de_GWD/.repo/geoip.dat + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}geoip.dat${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /opt/de_GWD/.repo/IPchnroute $IPchnroute_sha256sum) = "false" ]]; then +rm -rf /tmp/IPchnroute +wget --show-progress -cqO /tmp/IPchnroute https://raw.githubusercontent.com/jacyl4/chnroute/main/IPchnroute + if [[ $(checkSum /tmp/IPchnroute $IPchnroute_sha256sum) = "true" ]]; then + mv -f /tmp/IPchnroute /opt/de_GWD/.repo/IPchnroute + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}IPchnroute${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /opt/de_GWD/.repo/Domains.chn.txt $DomainsChn_sha256sum) = "false" ]]; then +rm -rf /tmp/Domains.chn.txt +wget --show-progress -cqO /tmp/Domains.chn.txt https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.chn.txt + if [[ $(checkSum /tmp/Domains.chn.txt $DomainsChn_sha256sum) = "true" ]]; then + mv -f /tmp/Domains.chn.txt /opt/de_GWD/.repo/Domains.chn.txt + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}Domains.chn.txt${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /opt/de_GWD/.repo/Domains.apple.txt $DomainsApple_sha256sum) = "false" ]]; then +rm -rf /tmp/Domains.apple.txt +wget --show-progress -cqO /tmp/Domains.apple.txt https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.apple.txt + if [[ $(checkSum /tmp/Domains.apple.txt $DomainsApple_sha256sum) = "true" ]]; then + mv -f /tmp/Domains.apple.txt /opt/de_GWD/.repo/Domains.apple.txt + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}Domains.apple.txt${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /opt/de_GWD/.repo/Domains.games.txt $DomainsGames_sha256sum) = "false" ]]; then +rm -rf /tmp/Domains.games.txt +wget --show-progress -cqO /tmp/Domains.games.txt https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/Domains.games.txt + if [[ $(checkSum /tmp/Domains.games.txt $DomainsGames_sha256sum) = "true" ]]; then + mv -f /tmp/Domains.games.txt /opt/de_GWD/.repo/Domains.games.txt + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}Domains.games.txt${RED} Download Failed${cRES}" + fi +fi + +if [[ $(checkSum /etc/dnsmasq.d/99-bogus-nxdomain.china.conf $bogusNxdomain_sha256sum) = "false" ]]; then +rm -rf /tmp/99-bogus-nxdomain.china.conf +wget --show-progress -cqO /tmp/99-bogus-nxdomain.china.conf https://raw.githubusercontent.com/jacyl4/chnroute/main/mosdns_chnlist/99-bogus-nxdomain.china.conf + if [[ $(checkSum /tmp/99-bogus-nxdomain.china.conf $bogusNxdomain_sha256sum) = "true" ]]; then + mv -f /tmp/99-bogus-nxdomain.china.conf /etc/dnsmasq.d/99-bogus-nxdomain.china.conf + else + echo -e "${WHITE}[ ${RED}✕ ${WHITE}]\c" && echo -e "\t${WHITE}bogus-nxdomain.china.conf${RED} Download Failed${cRES}" + fi +fi + + + +if [[ $(checkSum /opt/de_GWD/.repo/geosite.dat $geosite_sha256sum) = "true" ]]; then + cp -f /opt/de_GWD/.repo/geosite.dat /opt/de_GWD/vtrui/geosite.dat +fi + +if [[ $(checkSum /opt/de_GWD/.repo/geoip.dat $geoip_sha256sum) = "true" ]]; then + cp -f /opt/de_GWD/.repo/geoip.dat /opt/de_GWD/vtrui/geoip.dat +fi + + + +if [[ $(checkSum /opt/de_GWD/.repo/IPchnroute $IPchnroute_sha256sum) = "true" ]]; then +cp -f /opt/de_GWD/.repo/IPchnroute /opt/de_GWD/nftables/IP_CHNROUTE +sed -i '/^\s*$/d' /opt/de_GWD/nftables/IP_CHNROUTE +sed -i 's/$/,/g' /opt/de_GWD/nftables/IP_CHNROUTE +nft flush set ip de_GWD CHNROUTE +cat << EOF >/opt/de_GWD/nftables/SET_CHNROUTE.nft +#!/usr/sbin/nft -f +table ip de_GWD { + set CHNROUTE { + type ipv4_addr + flags interval + auto-merge + elements = { $(cat /opt/de_GWD/nftables/IP_CHNROUTE) } + } +} +EOF +chmod +x /opt/de_GWD/nftables/SET_CHNROUTE.nft +/opt/de_GWD/nftables/SET_CHNROUTE.nft +fi + +if [[ -n $(openssl x509 -enddate -noout -in /var/www/ssl/de_GWD.cer -checkend 259200 | grep "Certificate will expire") ]] && [[ -d "/root/.acme.sh" ]]; then +"/root/.acme.sh"/acme.sh --force --set-default-ca --server letsencrypt +"/root/.acme.sh"/acme.sh --force --cron --home "/root/.acme.sh" + +sslFolder=$(ls "/root/.acme.sh" | grep '_ecc') +cp -f "/root/.acme.sh"/$sslFolder/fullchain.cer /var/www/ssl/de_GWD.cer +cp -f "/root/.acme.sh"/$sslFolder/*.key /var/www/ssl/de_GWD.key +fi + +[[ -f "/var/www/ssl/update_ocsp_cache" ]] && /var/www/ssl/update_ocsp_cache >/dev/null 2>&1 + +[[ $1 = "u" ]] && service cron restart + +echo -e "${WHITE}[ ${GREEN}✓ ${WHITE}]\c" && echo -e "\t${WHITE}Update CHN Domain & IP rules${cRES}" diff --git a/resource/client/ui-script/ui_4h b/resource/client/ui-script/ui_4h new file mode 100755 index 000000000..a5a5c19bc --- /dev/null +++ b/resource/client/ui-script/ui_4h @@ -0,0 +1,18 @@ +#!/bin/bash +RED='\E[1;31m' +GREEN='\E[1;32m' +YELLOW='\E[1;33m' +BLUE='\E[1;34m' +PURPLE='\E[1;35m' +CYAN='\E[1;36m' +WHITE='\E[1;37m' +cRES='\E[0m' + + + +/opt/de_GWD/ui-smartDNS + +/opt/de_GWD/ui-DNSsplit + +[[ $1 = "r" ]] && pihole restartdns +[[ $1 = "n" ]] && systemctl restart nftables diff --git a/resource/client/ui-web/act/ADwlistDefault b/resource/client/ui-web/act/ADwlistDefault new file mode 100644 index 000000000..0515cee86 --- /dev/null +++ b/resource/client/ui-web/act/ADwlistDefault @@ -0,0 +1,236 @@ +albert.apple.com +captive.apple.com +humb.apple.com +static.ips.apple.com +tbsc.apple.com +time-ios.apple.com +time.apple.com +appldnld.apple.com +gg.apple.com +gnf-mdn.apple.com +gnf-mr.apple.com +gs.apple.com +ig.apple.com +mesu.apple.com +ns.itunes.apple.com +oscdn.apple.com +osrecovery.apple.com +skl.apple.com +swcdn.apple.com +swdist.apple.com +swdownload.apple.com +swpost.apple.com +swscan.apple.com +updates-http.cdn-apple.com +updates.cdn-apple.com +xp.apple.com +itunes.apple.com +ppq.apple.com +lcdn-registration.apple.com +crl.apple.com +crl.entrust.net +crl3.digicert.com +crl4.digicert.com +ocsp.apple.com +ocsp.digicert.com +ocsp.entrust.net +ocsp.verisign.net +gdmf.apple.com +deviceenrollment.apple.com +deviceservices-external.apple.com +identity.apple.com +iprofiles.apple.com +mdmenrollment.apple.com +setup.icloud.com +vpp.itunes.apple.com +s.click.taobao.com +0.client-channel.google.com +1drv.com +2.android.pool.ntp.org +akamaihd.net +akamaitechnologies.com +akamaized.net +amazonaws.com +android.clients.google.com +api.ipify.org +api.rlje.net +app-api.ted.com +appleid.apple.com +apps.skype.com +appsbackup-pa.clients6.google.com +appsbackup-pa.googleapis.com +apt.sonarr.tv +aspnetcdn.com +attestation.xboxlive.com +ax.phobos.apple.com.edgesuite.net +brightcove.net +c.s-microsoft.com +cdn.cloudflare.net +cdn.embedly.com +cdn.optimizely.com +cdn.vidible.tv +cdn2.optimizely.com +cdn3.optimizely.com +cdnjs.cloudflare.com +cert.mgt.xboxlive.com +clientconfig.passport.net +clients1.google.com +clients2.google.com +clients3.google.com +clients4.google.com +clients5.google.com +clients6.google.com +cpms.spop10.ams.plex.bz +cpms35.spop10.ams.plex.bz +cse.google.com +ctldl.windowsupdate.com +d2c8v52ll5s99u.cloudfront.net +d2gatte9o95jao.cloudfront.net +dashboard.plex.tv +dataplicity.com +def-vef.xboxlive.com +delivery.vidible.tv +dev.virtualearth.net +device.auth.xboxlive.com +display.ugc.bazaarvoice.com +displaycatalog.mp.microsoft.com +dl.delivery.mp.microsoft.com +dl.dropbox.com +dl.dropboxusercontent.com +dns.msftncsi.com +download.sonarr.tv +drift.com +driftt.com +dynupdate.no-ip.com +ecn.dev.virtualearth.net +edge.api.brightcove.com +eds.xboxlive.com +fonts.gstatic.com +forums.sonarr.tv +g.live.com +geo-prod.do.dsp.mp.microsoft.com +geo3.ggpht.com +giphy.com +github.com +github.io +googleapis.com +gravatar.com +gstatic.com +help.ui.xboxlive.com +hls.ted.com +i.ytimg.com +i1.ytimg.com +imagesak.secureserver.net +img.vidible.tv +imgix.net +imgs.xkcd.com +instantmessaging-pa.googleapis.com +intercom.io +jquery.com +jsdelivr.net +keystone.mwbsys.com +lastfm-img2.akamaized.net +licensing.xboxlive.com +live.com +login.live.com +login.microsoftonline.com +manifest.googlevideo.com +meta-db-worker02.pop.ric.plex.bz +meta.plex.bz +meta.plex.tv +microsoftonline.com +msftncsi.com +my.plexapp.com +nexusrules.officeapps.live.com +npr-news.streaming.adswizz.com +nine.plugins.plexapp.com +no-ip.com +node.plexapp.com +notify.xboxlive.com +ns1.dropbox.com +ns2.dropbox.com +o1.email.plex.tv +o2.sg0.plex.tv +office.com +office.net +office365.com +officeclient.microsoft.com +om.cbsi.com +onedrive.live.com +outlook.live.com +outlook.office365.com +placehold.it +placeholdit.imgix.net +players.brightcove.net +pricelist.skype.com +products.office.com +proxy.plex.bz +proxy.plex.tv +proxy02.pop.ord.plex.bz +pubsub.plex.bz +pubsub.plex.tv +raw.githubusercontent.com +redirector.googlevideo.com +res.cloudinary.com +s.gateway.messenger.live.com +s.marketwatch.com +s.youtube.com +s.ytimg.com +s1.wp.com +s2.youtube.com +s3.amazonaws.com +sa.symcb.com +secure.avangate.com +secure.brightcove.com +secure.surveymonkey.com +services.sonarr.tv +skyhook.sonarr.tv +spclient.wg.spotify.com +ssl.p.jwpcdn.com +staging.plex.tv +status.plex.tv +t.co +t0.ssl.ak.dynamic.tiles.virtualearth.net +t0.ssl.ak.tiles.virtualearth.net +tawk.to +tedcdn.com +themoviedb.com +thetvdb.com +tinyurl.com +title.auth.xboxlive.com +title.mgt.xboxlive.com +traffic.libsyn.com +tvdb2.plex.tv +tvthemes.plexapp.com +twimg.com +ui.skype.com +video-stats.l.google.com +videos.vidible.tv +widget-cdn.rpxnow.com +win10.ipv6.microsoft.com +wp.com +ws.audioscrobbler.com +www.dataplicity.com +www.googleapis.com +www.msftncsi.com +www.no-ip.com +www.youtube-nocookie.com +xbox.ipv6.microsoft.com +xboxexperiencesprod.experimentation.xboxlive.com +xflight.xboxlive.com +xkms.xboxlive.com +xsts.auth.xboxlive.com +youtu.be +youtube-nocookie.com +yt3.ggpht.com +zee.cws.conviva.com +pings.conviva.com +cws.conviva.com +livepassdl.conviva.com +gfwsl.geforce.com +appspot-preview.l.google.com +vidtech.cbsinteractive.com +continuum.dds.microsoft.com +connectivitycheck.gstatic.com +connectivitycheck.android.com +www.msftconnecttest.com \ No newline at end of file diff --git a/resource/client/ui-web/act/DNSclear.php b/resource/client/ui-web/act/DNSclear.php new file mode 100755 index 000000000..2062ce7ee --- /dev/null +++ b/resource/client/ui-web/act/DNSclear.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/DNSsave.php b/resource/client/ui-web/act/DNSsave.php new file mode 100755 index 000000000..283ebbb80 --- /dev/null +++ b/resource/client/ui-web/act/DNSsave.php @@ -0,0 +1,35 @@ + + +$v){ + $arr = explode(',',$v); + $hosts[$arr[1]] = $arr[0]; +} + +$DOHarray = array(); +array_push($DOHarray, "$DoH1", "$DoH2"); +$conf['dns']['dog'] = $DoGc; +$conf['dns']['doh'] = $DOHarray; +$conf['dns']['china'] = $dnsChina; +$conf['dns']['hosts'] = array(); +$conf['dns']['hosts'] = $hosts; +$newJsonString = json_encode($conf, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +file_put_contents('/opt/de_GWD/0conf', $newJsonString); + +exec('sudo /opt/de_GWD/ui_4h r n &'); +?> + \ No newline at end of file diff --git a/resource/client/ui-web/act/DoGsSave.php b/resource/client/ui-web/act/DoGsSave.php new file mode 100755 index 000000000..4f6042e71 --- /dev/null +++ b/resource/client/ui-web/act/DoGsSave.php @@ -0,0 +1,15 @@ + + + + diff --git a/resource/client/ui-web/act/DoGsStop.php b/resource/client/ui-web/act/DoGsStop.php new file mode 100755 index 000000000..733cde2fb --- /dev/null +++ b/resource/client/ui-web/act/DoGsStop.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/FWD0qr.php b/resource/client/ui-web/act/FWD0qr.php new file mode 100755 index 000000000..f542490d1 --- /dev/null +++ b/resource/client/ui-web/act/FWD0qr.php @@ -0,0 +1,13 @@ + + +address->serverName; +$FWD0port = $de_GWDconf->FORWARD->FWD0->port; +$FWD0uuid = $de_GWDconf->FORWARD->FWD0->uuid[$FWD0index-1]->FWD0uuid; + +print("vmess://$FWD0uuid@$serverDomain:$FWD0port?encryption=auto&type=tcp&tfo=1#$serverDomain:$FWD0port"); +?> + diff --git a/resource/client/ui-web/act/FWD0save.php b/resource/client/ui-web/act/FWD0save.php new file mode 100755 index 000000000..e88f7b20a --- /dev/null +++ b/resource/client/ui-web/act/FWD0save.php @@ -0,0 +1,17 @@ + + + + diff --git a/resource/client/ui-web/act/FWD0stop.php b/resource/client/ui-web/act/FWD0stop.php new file mode 100755 index 000000000..49dffbdfe --- /dev/null +++ b/resource/client/ui-web/act/FWD0stop.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/FWD1qr.php b/resource/client/ui-web/act/FWD1qr.php new file mode 100755 index 000000000..0f5545ecc --- /dev/null +++ b/resource/client/ui-web/act/FWD1qr.php @@ -0,0 +1,13 @@ + + +address->serverName; +$FWD1port = $de_GWDconf->FORWARD->FWD1->port; +$FWD1uuid = $de_GWDconf->FORWARD->FWD1->uuid[$FWD1index-1]->FWD1uuid; + +print("vmess://$FWD1uuid@$serverDomain:$FWD1port?encryption=auto&type=tcp&tfo=1#$serverDomain:$FWD1port"); +?> + diff --git a/resource/client/ui-web/act/FWD1save.php b/resource/client/ui-web/act/FWD1save.php new file mode 100755 index 000000000..ecac4f297 --- /dev/null +++ b/resource/client/ui-web/act/FWD1save.php @@ -0,0 +1,19 @@ + + + + diff --git a/resource/client/ui-web/act/FWD1stop.php b/resource/client/ui-web/act/FWD1stop.php new file mode 100755 index 000000000..76ebd7bb0 --- /dev/null +++ b/resource/client/ui-web/act/FWD1stop.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/NodeCUchange.php b/resource/client/ui-web/act/NodeCUchange.php new file mode 100755 index 000000000..fc2e20aa9 --- /dev/null +++ b/resource/client/ui-web/act/NodeCUchange.php @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeCUcheck.php b/resource/client/ui-web/act/NodeCUcheck.php new file mode 100755 index 000000000..af3dd2dcb --- /dev/null +++ b/resource/client/ui-web/act/NodeCUcheck.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeCUrules.php b/resource/client/ui-web/act/NodeCUrules.php new file mode 100755 index 000000000..bb8c3d5c1 --- /dev/null +++ b/resource/client/ui-web/act/NodeCUrules.php @@ -0,0 +1,23 @@ + + + + diff --git a/resource/client/ui-web/act/NodeCUswitch.php b/resource/client/ui-web/act/NodeCUswitch.php new file mode 100755 index 000000000..d551b4386 --- /dev/null +++ b/resource/client/ui-web/act/NodeCUswitch.php @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeChange.php b/resource/client/ui-web/act/NodeChange.php new file mode 100755 index 000000000..398edf680 --- /dev/null +++ b/resource/client/ui-web/act/NodeChange.php @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeDTchange.php b/resource/client/ui-web/act/NodeDTchange.php new file mode 100755 index 000000000..c273c2189 --- /dev/null +++ b/resource/client/ui-web/act/NodeDTchange.php @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeDTcheck.php b/resource/client/ui-web/act/NodeDTcheck.php new file mode 100755 index 000000000..594e2fe13 --- /dev/null +++ b/resource/client/ui-web/act/NodeDTcheck.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeDTrules.php b/resource/client/ui-web/act/NodeDTrules.php new file mode 100755 index 000000000..2d216b655 --- /dev/null +++ b/resource/client/ui-web/act/NodeDTrules.php @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeDTswitch.php b/resource/client/ui-web/act/NodeDTswitch.php new file mode 100755 index 000000000..f39a985db --- /dev/null +++ b/resource/client/ui-web/act/NodeDTswitch.php @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeOne.php b/resource/client/ui-web/act/NodeOne.php new file mode 100755 index 000000000..bb8ff7b91 --- /dev/null +++ b/resource/client/ui-web/act/NodeOne.php @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeSMcheck.php b/resource/client/ui-web/act/NodeSMcheck.php new file mode 100755 index 000000000..c617ef60b --- /dev/null +++ b/resource/client/ui-web/act/NodeSMcheck.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/NodeSMrules.php b/resource/client/ui-web/act/NodeSMrules.php new file mode 100755 index 000000000..0ecec7c4f --- /dev/null +++ b/resource/client/ui-web/act/NodeSMrules.php @@ -0,0 +1,14 @@ + + + + diff --git a/resource/client/ui-web/act/NodeSave.php b/resource/client/ui-web/act/NodeSave.php new file mode 100755 index 000000000..061e474ef --- /dev/null +++ b/resource/client/ui-web/act/NodeSave.php @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/RproxyCsave.php b/resource/client/ui-web/act/RproxyCsave.php new file mode 100755 index 000000000..307ff7b94 --- /dev/null +++ b/resource/client/ui-web/act/RproxyCsave.php @@ -0,0 +1,23 @@ + + + + diff --git a/resource/client/ui-web/act/RproxyCstop.php b/resource/client/ui-web/act/RproxyCstop.php new file mode 100755 index 000000000..4dcc9241d --- /dev/null +++ b/resource/client/ui-web/act/RproxyCstop.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/RproxyS0qr.php b/resource/client/ui-web/act/RproxyS0qr.php new file mode 100755 index 000000000..9a3d2d206 --- /dev/null +++ b/resource/client/ui-web/act/RproxyS0qr.php @@ -0,0 +1,13 @@ + + +address->serverName; +$RproxyS0port = $de_GWDconf->FORWARD->Rproxy->server->tunnel->port; +$RproxyS0uuid = $de_GWDconf->FORWARD->Rproxy->server->inUUID[$RproxyS0index-1]->RproxyS0uuid; + +print("vmess://$RproxyS0uuid@$serverDomain:$RproxyS0port?encryption=auto&type=tcp&tfo=1#$serverDomain:$RproxyS0port"); +?> + diff --git a/resource/client/ui-web/act/RproxySsave.php b/resource/client/ui-web/act/RproxySsave.php new file mode 100755 index 000000000..3a27e4c11 --- /dev/null +++ b/resource/client/ui-web/act/RproxySsave.php @@ -0,0 +1,25 @@ + + + + diff --git a/resource/client/ui-web/act/RproxySstop.php b/resource/client/ui-web/act/RproxySstop.php new file mode 100755 index 000000000..0b8d3096f --- /dev/null +++ b/resource/client/ui-web/act/RproxySstop.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/WGgenCkey.php b/resource/client/ui-web/act/WGgenCkey.php new file mode 100755 index 000000000..f10c2b746 --- /dev/null +++ b/resource/client/ui-web/act/WGgenCkey.php @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/WGgenSkey.php b/resource/client/ui-web/act/WGgenSkey.php new file mode 100755 index 000000000..0ef329ee4 --- /dev/null +++ b/resource/client/ui-web/act/WGgenSkey.php @@ -0,0 +1,6 @@ + + +/dev/null 2>&1 &'); +?> + \ No newline at end of file diff --git a/resource/client/ui-web/act/WGqr.php b/resource/client/ui-web/act/WGqr.php new file mode 100755 index 000000000..089624d0a --- /dev/null +++ b/resource/client/ui-web/act/WGqr.php @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/adBregexDefault b/resource/client/ui-web/act/adBregexDefault new file mode 100644 index 000000000..9034812f3 --- /dev/null +++ b/resource/client/ui-web/act/adBregexDefault @@ -0,0 +1,22 @@ +^ad([sxv]?[0-9]*|system)[_.-]([^.[:space:]]+\.){1,}|[_.-]ad([sxv]?[0-9]*|system)[_.-] +^(.+[_.-])?adse?rv(er?|ice)?s?[0-9]*[_.-] +^(.+[_.-])?ad[sxv]?[0-9]*[_.-] +^(.+[_.-])??m?ad[sxv]?[0-9]*[_.-] +^(.+[_.-])?telemetry[_.-] +^adim(age|g)s?[0-9]*[_.-] +^adtrack(er|ing)?[0-9]*[_.-] +^advert(s|is(ing|ements?))?[0-9]*[_.-] +^aff(iliat(es?|ion))?[_.-] +^analytics?[_.-] +^banners?[_.-] +^beacons?[0-9]*[_.-] +^clicks?[_.-] +^count(ers?)?[0-9]*[_.-] +^mads\. +^pixels?[-.] +^stat(s|istics)?[0-9]*[_.-] +^tracking?[0-9]*[_.-] +^traff(ic)?[-.] +(^|\.)roku\.com$ +(^|\.)samsungads\.com$ +(^|\.)sn-cu-aigs7\.googlevideo\.com$ \ No newline at end of file diff --git a/resource/client/ui-web/act/adWregexDefault b/resource/client/ui-web/act/adWregexDefault new file mode 100644 index 000000000..ff998a6a8 --- /dev/null +++ b/resource/client/ui-web/act/adWregexDefault @@ -0,0 +1,20 @@ +(^|\.)apple\.com$ +(^|\.)appattest\.apple\.com$ +(^|\.)apple-cloudkit\.com$ +(^|\.)apple-livephotoskit\.com$ +(^|\.)apps\.apple\.com$ +(^|\.)apzones\.com$ +(^|\.)business\.apple\.com$ +(^|\.)cdn-apple\.com$ +(^|\.)deimos3\.apple\.com$ +(^|\.)digicert\.com$ +(^|\.)gc\.apple\.com$ +(^|\.)gg.*apple\.com$ +(^|\.)itunes\.apple\.com$ +(^|\.)iwork\.apple\.com$ +(^|\.)mesu\.apple\.com$ +(^|\.)mzstatic\.com$ +(^|\.)push\.apple\.com$ +(^|\.)school\.apple\.com$ +(^|\.)symcd\.com$ +(^|\.)[s1-5\.]*?symcb\.com$ \ No newline at end of file diff --git a/resource/client/ui-web/act/adlistsDefault b/resource/client/ui-web/act/adlistsDefault new file mode 100644 index 000000000..24f77df63 --- /dev/null +++ b/resource/client/ui-web/act/adlistsDefault @@ -0,0 +1,8 @@ +https://raw.githubusercontent.com/kboghdady/youTube_ads_4_pi-hole/master/youtubelist.txt +https://raw.githubusercontent.com/neoFelhz/neohosts/gh-pages/full/hosts +https://raw.githubusercontent.com/ilpl/ad-hosts/master/hosts +https://raw.githubusercontent.com/jdlingyu/ad-wars/master/hosts +https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&sho%20wintro=0&mimetype=plaintext +https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt +https://share.is26.com/subscribe/adblock.hosts +https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/reject-list.txt \ No newline at end of file diff --git a/resource/client/ui-web/act/autoUpdateHour.php b/resource/client/ui-web/act/autoUpdateHour.php new file mode 100755 index 000000000..862a2f84c --- /dev/null +++ b/resource/client/ui-web/act/autoUpdateHour.php @@ -0,0 +1,13 @@ + + + + diff --git a/resource/client/ui-web/act/backup.php b/resource/client/ui-web/act/backup.php new file mode 100755 index 000000000..7ee1c0e11 --- /dev/null +++ b/resource/client/ui-web/act/backup.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/backupBitwarden.php b/resource/client/ui-web/act/backupBitwarden.php new file mode 100755 index 000000000..433d0395d --- /dev/null +++ b/resource/client/ui-web/act/backupBitwarden.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/backupJellyfin.php b/resource/client/ui-web/act/backupJellyfin.php new file mode 100755 index 000000000..f8a5fbf9c --- /dev/null +++ b/resource/client/ui-web/act/backupJellyfin.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/block53off.php b/resource/client/ui-web/act/block53off.php new file mode 100755 index 000000000..28189c1a8 --- /dev/null +++ b/resource/client/ui-web/act/block53off.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/block53on.php b/resource/client/ui-web/act/block53on.php new file mode 100755 index 000000000..b4fb9d3fe --- /dev/null +++ b/resource/client/ui-web/act/block53on.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/changeNodeSS.php b/resource/client/ui-web/act/changeNodeSS.php new file mode 100755 index 000000000..712aa4af5 --- /dev/null +++ b/resource/client/ui-web/act/changeNodeSS.php @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/changeNodeSS0.php b/resource/client/ui-web/act/changeNodeSS0.php new file mode 100755 index 000000000..3dbb19dce --- /dev/null +++ b/resource/client/ui-web/act/changeNodeSS0.php @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/checkCER.php b/resource/client/ui-web/act/checkCER.php new file mode 100755 index 000000000..33385d88b --- /dev/null +++ b/resource/client/ui-web/act/checkCER.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/checkDDNS3322.php b/resource/client/ui-web/act/checkDDNS3322.php new file mode 100755 index 000000000..8ead0e8e1 --- /dev/null +++ b/resource/client/ui-web/act/checkDDNS3322.php @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/checkDDNScf.php b/resource/client/ui-web/act/checkDDNScf.php new file mode 100755 index 000000000..3af901347 --- /dev/null +++ b/resource/client/ui-web/act/checkDDNScf.php @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/checkDDNSip.php b/resource/client/ui-web/act/checkDDNSip.php new file mode 100755 index 000000000..b71149add --- /dev/null +++ b/resource/client/ui-web/act/checkDDNSip.php @@ -0,0 +1,5 @@ + diff --git a/resource/client/ui-web/act/checkWG.php b/resource/client/ui-web/act/checkWG.php new file mode 100755 index 000000000..4695a9a4c --- /dev/null +++ b/resource/client/ui-web/act/checkWG.php @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/genCER.php b/resource/client/ui-web/act/genCER.php new file mode 100755 index 000000000..16a9fbc4c --- /dev/null +++ b/resource/client/ui-web/act/genCER.php @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/getNFSlist.php b/resource/client/ui-web/act/getNFSlist.php new file mode 100755 index 000000000..e6d25c6af --- /dev/null +++ b/resource/client/ui-web/act/getNFSlist.php @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/installBitwarden.php b/resource/client/ui-web/act/installBitwarden.php new file mode 100755 index 000000000..2063001e7 --- /dev/null +++ b/resource/client/ui-web/act/installBitwarden.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installDocker.php b/resource/client/ui-web/act/installDocker.php new file mode 100755 index 000000000..a3ec6ef5a --- /dev/null +++ b/resource/client/ui-web/act/installDocker.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installFileRun.php b/resource/client/ui-web/act/installFileRun.php new file mode 100755 index 000000000..c6c38ab42 --- /dev/null +++ b/resource/client/ui-web/act/installFileRun.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installJellyfin.php b/resource/client/ui-web/act/installJellyfin.php new file mode 100755 index 000000000..12c90a2ce --- /dev/null +++ b/resource/client/ui-web/act/installJellyfin.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installMariaDB.php b/resource/client/ui-web/act/installMariaDB.php new file mode 100755 index 000000000..ad5a45375 --- /dev/null +++ b/resource/client/ui-web/act/installMariaDB.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installNFS.php b/resource/client/ui-web/act/installNFS.php new file mode 100755 index 000000000..ec671c97d --- /dev/null +++ b/resource/client/ui-web/act/installNFS.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installWG.php b/resource/client/ui-web/act/installWG.php new file mode 100755 index 000000000..88acfd141 --- /dev/null +++ b/resource/client/ui-web/act/installWG.php @@ -0,0 +1,6 @@ + + + + diff --git a/resource/client/ui-web/act/installZ.php b/resource/client/ui-web/act/installZ.php new file mode 100755 index 000000000..87f00d502 --- /dev/null +++ b/resource/client/ui-web/act/installZ.php @@ -0,0 +1,6 @@ + + +/dev/null 2>&1 &'); +?> + diff --git a/resource/client/ui-web/act/markThis.php b/resource/client/ui-web/act/markThis.php new file mode 100755 index 000000000..a8cce3bb9 --- /dev/null +++ b/resource/client/ui-web/act/markThis.php @@ -0,0 +1,13 @@ + + +/dev/null 2>&1 &'); +?> + \ No newline at end of file diff --git a/resource/client/ui-web/act/offDDNS3322.php b/resource/client/ui-web/act/offDDNS3322.php new file mode 100755 index 000000000..b4a14fc20 --- /dev/null +++ b/resource/client/ui-web/act/offDDNS3322.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/offDDNScf.php b/resource/client/ui-web/act/offDDNScf.php new file mode 100755 index 000000000..c855d598e --- /dev/null +++ b/resource/client/ui-web/act/offDDNScf.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/offDHCP.php b/resource/client/ui-web/act/offDHCP.php new file mode 100755 index 000000000..cb99825a4 --- /dev/null +++ b/resource/client/ui-web/act/offDHCP.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/offNFS.php b/resource/client/ui-web/act/offNFS.php new file mode 100755 index 000000000..3abf55953 --- /dev/null +++ b/resource/client/ui-web/act/offNFS.php @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/offWG.php b/resource/client/ui-web/act/offWG.php new file mode 100755 index 000000000..8871de72b --- /dev/null +++ b/resource/client/ui-web/act/offWG.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/onDDNS3322.php b/resource/client/ui-web/act/onDDNS3322.php new file mode 100755 index 000000000..9a71eb83b --- /dev/null +++ b/resource/client/ui-web/act/onDDNS3322.php @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/onDDNScf.php b/resource/client/ui-web/act/onDDNScf.php new file mode 100755 index 000000000..d8bf51d80 --- /dev/null +++ b/resource/client/ui-web/act/onDDNScf.php @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/onDHCP.php b/resource/client/ui-web/act/onDHCP.php new file mode 100755 index 000000000..d71c00328 --- /dev/null +++ b/resource/client/ui-web/act/onDHCP.php @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/onNFS.php b/resource/client/ui-web/act/onNFS.php new file mode 100755 index 000000000..29773061b --- /dev/null +++ b/resource/client/ui-web/act/onNFS.php @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/onWG.php b/resource/client/ui-web/act/onWG.php new file mode 100755 index 000000000..7eb64302a --- /dev/null +++ b/resource/client/ui-web/act/onWG.php @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/pingTCP.php b/resource/client/ui-web/act/pingTCP.php new file mode 100755 index 000000000..b4bc1a3b2 --- /dev/null +++ b/resource/client/ui-web/act/pingTCP.php @@ -0,0 +1,5 @@ + diff --git a/resource/client/ui-web/act/pingTCPDOH1.php b/resource/client/ui-web/act/pingTCPDOH1.php new file mode 100755 index 000000000..71d0bd171 --- /dev/null +++ b/resource/client/ui-web/act/pingTCPDOH1.php @@ -0,0 +1,4 @@ + diff --git a/resource/client/ui-web/act/pingTCPDOH2.php b/resource/client/ui-web/act/pingTCPDOH2.php new file mode 100755 index 000000000..0509abedd --- /dev/null +++ b/resource/client/ui-web/act/pingTCPDOH2.php @@ -0,0 +1,4 @@ + diff --git a/resource/client/ui-web/act/pingTCPDoG.php b/resource/client/ui-web/act/pingTCPDoG.php new file mode 100755 index 000000000..4c57836eb --- /dev/null +++ b/resource/client/ui-web/act/pingTCPDoG.php @@ -0,0 +1,4 @@ + diff --git a/resource/client/ui-web/act/proxyRestart.php b/resource/client/ui-web/act/proxyRestart.php new file mode 100755 index 000000000..b4532bc9d --- /dev/null +++ b/resource/client/ui-web/act/proxyRestart.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/proxyStop.php b/resource/client/ui-web/act/proxyStop.php new file mode 100755 index 000000000..095c17a71 --- /dev/null +++ b/resource/client/ui-web/act/proxyStop.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/reboot.php b/resource/client/ui-web/act/reboot.php new file mode 100755 index 000000000..a5838ce69 --- /dev/null +++ b/resource/client/ui-web/act/reboot.php @@ -0,0 +1,15 @@ + + +/dev/null 2>&1 &'); +?> + \ No newline at end of file diff --git a/resource/client/ui-web/act/restore.php b/resource/client/ui-web/act/restore.php new file mode 100755 index 000000000..8bd13188b --- /dev/null +++ b/resource/client/ui-web/act/restore.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/restoreBitwarden.php b/resource/client/ui-web/act/restoreBitwarden.php new file mode 100755 index 000000000..b03807935 --- /dev/null +++ b/resource/client/ui-web/act/restoreBitwarden.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/restoreJellyfin.php b/resource/client/ui-web/act/restoreJellyfin.php new file mode 100755 index 000000000..39987e847 --- /dev/null +++ b/resource/client/ui-web/act/restoreJellyfin.php @@ -0,0 +1,11 @@ + + + + diff --git a/resource/client/ui-web/act/speedT.php b/resource/client/ui-web/act/speedT.php new file mode 100755 index 000000000..47957f136 --- /dev/null +++ b/resource/client/ui-web/act/speedT.php @@ -0,0 +1,4 @@ + diff --git a/resource/client/ui-web/act/submitADList.php b/resource/client/ui-web/act/submitADList.php new file mode 100755 index 000000000..a382aac96 --- /dev/null +++ b/resource/client/ui-web/act/submitADList.php @@ -0,0 +1,39 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/submitListBW.php b/resource/client/ui-web/act/submitListBW.php new file mode 100755 index 000000000..e8ae6d7d3 --- /dev/null +++ b/resource/client/ui-web/act/submitListBW.php @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/testBaidu.php b/resource/client/ui-web/act/testBaidu.php new file mode 100755 index 000000000..a0626b66b --- /dev/null +++ b/resource/client/ui-web/act/testBaidu.php @@ -0,0 +1,12 @@ + diff --git a/resource/client/ui-web/act/testGlobal.php b/resource/client/ui-web/act/testGlobal.php new file mode 100755 index 000000000..33729e1b8 --- /dev/null +++ b/resource/client/ui-web/act/testGlobal.php @@ -0,0 +1,12 @@ + diff --git a/resource/client/ui-web/act/updateRun.php b/resource/client/ui-web/act/updateRun.php new file mode 100755 index 000000000..c84b45d88 --- /dev/null +++ b/resource/client/ui-web/act/updateRun.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/updateSave.php b/resource/client/ui-web/act/updateSave.php new file mode 100755 index 000000000..807b4db2f --- /dev/null +++ b/resource/client/ui-web/act/updateSave.php @@ -0,0 +1,31 @@ + + + + \ No newline at end of file diff --git a/resource/client/ui-web/act/uptime.php b/resource/client/ui-web/act/uptime.php new file mode 100755 index 000000000..c73af73c0 --- /dev/null +++ b/resource/client/ui-web/act/uptime.php @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/resource/client/ui-web/app.php b/resource/client/ui-web/app.php new file mode 100755 index 000000000..a7b1fadba --- /dev/null +++ b/resource/client/ui-web/app.php @@ -0,0 +1,567 @@ + + + + + + + + + + + + + +应用 + + + + + + + + + + + + + + + + + + + + +app->jellyfin; ?> + + +app->bitwarden; ?> + + + + + + + + +
+ + + + + +
+ +
+ + + + + + + + +
+ + +
+ + +
+
+ + NFS挂载 + + + + + + + + + +
+ +
+ +
+
+ 挂载点 +
+ +
+ +
+
+ NFS服务器地址 +
+ +
+
+ $NFSaddress + +
+
+EOT; +} +?> + + + +
+
+ +
+
+ + Docker + + + + + + +
+ +
+
+
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+
+ +
+
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + diff --git a/resource/client/ui-web/auth.php b/resource/client/ui-web/auth.php new file mode 100755 index 000000000..086ff4345 --- /dev/null +++ b/resource/client/ui-web/auth.php @@ -0,0 +1,51 @@ +address->PWD; + if(isset($PWDhash)) + { + $GWDpwhash = $PWDhash; + } + else + { + $GWDpwhash = ""; + } + + + if(isset($_GET['logout'])) + { + unset($_SESSION["GWDhash"]); + setcookie('persistentlogin', ''); + exit(); + } + $auth = false; + + + if(isset($_GET['gwdpw'])) + { + $logininput = hash('sha256',hash('sha256',$_GET['gwdpw'])); + if( $GWDpwhash === $logininput ) + { + $_SESSION["GWDhash"] = $GWDpwhash; + $auth = true; + } + else + { + $auth = false; + } + } + else if (isset($_SESSION["GWDhash"])) + { + if($_SESSION["GWDhash"] === $GWDpwhash) + { + $auth = true; + } + else + { + $auth = false; + } + } + else + { + $auth = false; + } +?> \ No newline at end of file diff --git a/resource/client/ui-web/css/animation.css b/resource/client/ui-web/css/animation.css new file mode 100755 index 000000000..65d4a3bed --- /dev/null +++ b/resource/client/ui-web/css/animation.css @@ -0,0 +1,102 @@ +/*cloud*/ +.cloud{ + margin-top: -5px; + margin-left: -20px; + width: 4px; + height: 10px; + opacity: 0.5; + position: absolute; + box-shadow: 6px 0px 0px 0px rgba(40,167,69,1), + 12px 0px 0px 0px rgba(40,167,69,1), + 18px 0px 0px 0px rgba(40,167,69,1), + 24px 0px 0px 0px rgba(40,167,69,1), + 30px 0px 0px 0px rgba(40,167,69,1), + 36px 0px 0px 0px rgba(40,167,69,1); + + -webkit-animation: rain 1s linear infinite alternate; + -moz-animation: rain 1s linear infinite alternate; + animation: rain 1s linear infinite alternate; +} +.cloud:after{ + width: 40px; + height: 10px; + position: absolute; + content: ""; + background-color: rgba(40,167,69,1); + top: 0px; + opacity: 1; + -webkit-animation: line_flow 2s linear infinite reverse; + -moz-animation: line_flow 2s linear infinite reverse; + animation: line_flow 2s linear infinite reverse; +} + +@-webkit-keyframes rain{ + 0%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,1), + 12px 0px 0px 0px rgba(40,167,69,0.9), + 18px 0px 0px 0px rgba(40,167,69,0.7), + 24px 0px 0px 0px rgba(40,167,69,0.6), + 30px 0px 0px 0px rgba(40,167,69,0.3), + 36px 0px 0px 0px rgba(40,167,69,0.2); + } + 100%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,0.2), + 12px 0px 0px 0px rgba(40,167,69,0.3), + 18px 0px 0px 0px rgba(40,167,69,0.6), + 24px 0px 0px 0px rgba(40,167,69,0.7), + 30px 0px 0px 0px rgba(40,167,69,0.9), + 36px 0px 0px 0px rgba(40,167,69,1); + opacity: 1; + } +} +@-moz-keyframes rain{ + 0%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,1), + 12px 0px 0px 0px rgba(40,167,69,0.9), + 18px 0px 0px 0px rgba(40,167,69,0.7), + 24px 0px 0px 0px rgba(40,167,69,0.6), + 30px 0px 0px 0px rgba(40,167,69,0.3), + 36px 0px 0px 0px rgba(40,167,69,0.2); + } + 100%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,0.2), + 12px 0px 0px 0px rgba(40,167,69,0.3), + 18px 0px 0px 0px rgba(40,167,69,0.6), + 24px 0px 0px 0px rgba(40,167,69,0.7), + 30px 0px 0px 0px rgba(40,167,69,0.9), + 36px 0px 0px 0px rgba(40,167,69,1); + opacity: 1; + } +} +@keyframes rain{ + 0%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,1), + 12px 0px 0px 0px rgba(40,167,69,0.9), + 18px 0px 0px 0px rgba(40,167,69,0.7), + 24px 0px 0px 0px rgba(40,167,69,0.6), + 30px 0px 0px 0px rgba(40,167,69,0.3), + 36px 0px 0px 0px rgba(40,167,69,0.2); + } + 100%{ + box-shadow: 6px 0px 0px 0px rgba(40,167,69,0.2), + 12px 0px 0px 0px rgba(40,167,69,0.3), + 18px 0px 0px 0px rgba(40,167,69,0.6), + 24px 0px 0px 0px rgba(40,167,69,0.7), + 30px 0px 0px 0px rgba(40,167,69,0.9), + 36px 0px 0px 0px rgba(40,167,69,1); + opacity: 1; + } +} + +@-webkit-keyframes line_flow{ + 0%{ width: 0px;} + 100%{width: 40px;} +} +@-moz-keyframes line_flow{ + 0%{ width: 0px;} + 100%{width: 40px;} +} +@keyframes line_flow{ + 0%{ width: 0px;} + 100%{width: 40px;} +} diff --git a/resource/client/ui-web/css/sb-admin.css b/resource/client/ui-web/css/sb-admin.css new file mode 100755 index 000000000..88836d67e --- /dev/null +++ b/resource/client/ui-web/css/sb-admin.css @@ -0,0 +1,10914 @@ +/*! + * Start Bootstrap - SB Admin v5.1.1 (https://startbootstrap.com/template-overviews/sb-admin) + * Copyright 2013-2019 Start Bootstrap + * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-sb-admin/blob/master/LICENSE) + */ + +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +:root { + --blue: #007bff; + --indigo: #6610f2; + --purple: #6f42c1; + --pink: #e83e8c; + --red: #dc3545; + --orange: #fd7e14; + --yellow: #ffc107; + --green: #28a745; + --teal: #20c997; + --cyan: #17a2b8; + --white: #fff; + --gray: #6c757d; + --gray-dark: #343a40; + --primary: #007bff; + --secondary: #6c757d; + --success: #28a745; + --info: #17a2b8; + --warning: #ffc107; + --danger: #dc3545; + --light: #f8f9fa; + --dark: #343a40; + --breakpoint-xs: 0; + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +*, +*::before, +*::after { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { + display: block; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fff; +} + +[tabindex="-1"]:focus { + outline: 0 !important; +} + +hr { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 0; + overflow: visible; +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 0.5rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-original-title] { + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + border-bottom: 0; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + color: #007bff; + text-decoration: none; + background-color: transparent; +} + +a:hover { + color: #0056b3; + text-decoration: underline; +} + +a:not([href]):not([tabindex]) { + color: inherit; + text-decoration: none; +} + +a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { + color: inherit; + text-decoration: none; +} + +a:not([href]):not([tabindex]):focus { + outline: 0; +} + +pre, +code, +kbd, +samp { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-size: 1em; +} + +pre { + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; +} + +figure { + margin: 0 0 1rem; +} + +img { + vertical-align: middle; + border-style: none; +} + +svg { + overflow: hidden; + vertical-align: middle; +} + +table { + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; + caption-side: bottom; +} + +th { + text-align: inherit; +} + +label { + display: inline-block; + margin-bottom: 0.5rem; +} + +button { + border-radius: 0; +} + +button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +input { + overflow: visible; +} + +button, +select { + text-transform: none; +} + +select { + word-wrap: normal; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button:not(:disabled), +[type="button"]:not(:disabled), +[type="reset"]:not(:disabled), +[type="submit"]:not(:disabled) { + cursor: pointer; +} + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + padding: 0; + border-style: none; +} + +input[type="radio"], +input[type="checkbox"] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} + +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + -webkit-appearance: listbox; +} + +textarea { + overflow: auto; + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + max-width: 100%; + padding: 0; + margin-bottom: .5rem; + font-size: 1.5rem; + line-height: inherit; + color: inherit; + white-space: normal; +} + +progress { + vertical-align: baseline; +} + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: none; +} + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +summary { + display: list-item; + cursor: pointer; +} + +template { + display: none; +} + +[hidden] { + display: none !important; +} + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; +} + +h1, .h1 { + font-size: 2.5rem; +} + +h2, .h2 { + font-size: 2rem; +} + +h3, .h3 { + font-size: 1.75rem; +} + +h4, .h4 { + font-size: 1.5rem; +} + +h5, .h5 { + font-size: 1.25rem; +} + +h6, .h6 { + font-size: 1rem; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +hr { + margin-top: 1rem; + margin-bottom: 1rem; + border: 0; + border-top: 1px solid rgba(0, 0, 0, 0.1); +} + +small, +.small { + font-size: 80%; + font-weight: 400; +} + +mark, +.mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} + +.blockquote-footer { + display: block; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 90%; + color: #6c757d; +} + +code { + font-size: 87.5%; + color: #e83e8c; + word-break: break-word; +} + +a > code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 87.5%; + color: #fff; + background-color: #212529; + border-radius: 0.2rem; +} + +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: 700; +} + +pre { + display: block; + font-size: 87.5%; + color: #212529; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +.container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container { + max-width: 1140px; + } +} + +.container-fluid { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.row { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + +.no-gutters { + margin-right: 0; + margin-left: 0; +} + +.no-gutters > .col, +.no-gutters > [class*="col-"] { + padding-right: 0; + padding-left: 0; +} + +.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, +.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, +.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, +.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, +.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, +.col-xl-auto { + position: relative; + width: 100%; + padding-right: 15px; + padding-left: 15px; +} + +.col { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; +} + +.col-auto { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; +} + +.col-1 { + -webkit-box-flex: 0; + -ms-flex: 0 0 8.33333%; + flex: 0 0 8.33333%; + max-width: 8.33333%; +} + +.col-2 { + -webkit-box-flex: 0; + -ms-flex: 0 0 16.66667%; + flex: 0 0 16.66667%; + max-width: 16.66667%; +} + +.col-3 { + -webkit-box-flex: 0; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.col-4 { + -webkit-box-flex: 0; + -ms-flex: 0 0 33.33333%; + flex: 0 0 33.33333%; + max-width: 33.33333%; +} + +.col-5 { + -webkit-box-flex: 0; + -ms-flex: 0 0 41.66667%; + flex: 0 0 41.66667%; + max-width: 41.66667%; +} + +.col-6 { + -webkit-box-flex: 0; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.col-7 { + -webkit-box-flex: 0; + -ms-flex: 0 0 58.33333%; + flex: 0 0 58.33333%; + max-width: 58.33333%; +} + +.col-8 { + -webkit-box-flex: 0; + -ms-flex: 0 0 66.66667%; + flex: 0 0 66.66667%; + max-width: 66.66667%; +} + +.col-9 { + -webkit-box-flex: 0; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; +} + +.col-10 { + -webkit-box-flex: 0; + -ms-flex: 0 0 83.33333%; + flex: 0 0 83.33333%; + max-width: 83.33333%; +} + +.col-11 { + -webkit-box-flex: 0; + -ms-flex: 0 0 91.66667%; + flex: 0 0 91.66667%; + max-width: 91.66667%; +} + +.col-12 { + -webkit-box-flex: 0; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.order-first { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1; +} + +.order-last { + -webkit-box-ordinal-group: 14; + -ms-flex-order: 13; + order: 13; +} + +.order-0 { + -webkit-box-ordinal-group: 1; + -ms-flex-order: 0; + order: 0; +} + +.order-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; +} + +.order-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; +} + +.order-3 { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; +} + +.order-4 { + -webkit-box-ordinal-group: 5; + -ms-flex-order: 4; + order: 4; +} + +.order-5 { + -webkit-box-ordinal-group: 6; + -ms-flex-order: 5; + order: 5; +} + +.order-6 { + -webkit-box-ordinal-group: 7; + -ms-flex-order: 6; + order: 6; +} + +.order-7 { + -webkit-box-ordinal-group: 8; + -ms-flex-order: 7; + order: 7; +} + +.order-8 { + -webkit-box-ordinal-group: 9; + -ms-flex-order: 8; + order: 8; +} + +.order-9 { + -webkit-box-ordinal-group: 10; + -ms-flex-order: 9; + order: 9; +} + +.order-10 { + -webkit-box-ordinal-group: 11; + -ms-flex-order: 10; + order: 10; +} + +.order-11 { + -webkit-box-ordinal-group: 12; + -ms-flex-order: 11; + order: 11; +} + +.order-12 { + -webkit-box-ordinal-group: 13; + -ms-flex-order: 12; + order: 12; +} + +.offset-1 { + margin-left: 8.33333%; +} + +.offset-2 { + margin-left: 16.66667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333%; +} + +.offset-5 { + margin-left: 41.66667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333%; +} + +.offset-8 { + margin-left: 66.66667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333%; +} + +.offset-11 { + margin-left: 91.66667%; +} + +@media (min-width: 576px) { + .col-sm { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-sm-auto { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-sm-1 { + -webkit-box-flex: 0; + -ms-flex: 0 0 8.33333%; + flex: 0 0 8.33333%; + max-width: 8.33333%; + } + .col-sm-2 { + -webkit-box-flex: 0; + -ms-flex: 0 0 16.66667%; + flex: 0 0 16.66667%; + max-width: 16.66667%; + } + .col-sm-3 { + -webkit-box-flex: 0; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-sm-4 { + -webkit-box-flex: 0; + -ms-flex: 0 0 33.33333%; + flex: 0 0 33.33333%; + max-width: 33.33333%; + } + .col-sm-5 { + -webkit-box-flex: 0; + -ms-flex: 0 0 41.66667%; + flex: 0 0 41.66667%; + max-width: 41.66667%; + } + .col-sm-6 { + -webkit-box-flex: 0; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-sm-7 { + -webkit-box-flex: 0; + -ms-flex: 0 0 58.33333%; + flex: 0 0 58.33333%; + max-width: 58.33333%; + } + .col-sm-8 { + -webkit-box-flex: 0; + -ms-flex: 0 0 66.66667%; + flex: 0 0 66.66667%; + max-width: 66.66667%; + } + .col-sm-9 { + -webkit-box-flex: 0; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-sm-10 { + -webkit-box-flex: 0; + -ms-flex: 0 0 83.33333%; + flex: 0 0 83.33333%; + max-width: 83.33333%; + } + .col-sm-11 { + -webkit-box-flex: 0; + -ms-flex: 0 0 91.66667%; + flex: 0 0 91.66667%; + max-width: 91.66667%; + } + .col-sm-12 { + -webkit-box-flex: 0; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-sm-first { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1; + } + .order-sm-last { + -webkit-box-ordinal-group: 14; + -ms-flex-order: 13; + order: 13; + } + .order-sm-0 { + -webkit-box-ordinal-group: 1; + -ms-flex-order: 0; + order: 0; + } + .order-sm-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .order-sm-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .order-sm-3 { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .order-sm-4 { + -webkit-box-ordinal-group: 5; + -ms-flex-order: 4; + order: 4; + } + .order-sm-5 { + -webkit-box-ordinal-group: 6; + -ms-flex-order: 5; + order: 5; + } + .order-sm-6 { + -webkit-box-ordinal-group: 7; + -ms-flex-order: 6; + order: 6; + } + .order-sm-7 { + -webkit-box-ordinal-group: 8; + -ms-flex-order: 7; + order: 7; + } + .order-sm-8 { + -webkit-box-ordinal-group: 9; + -ms-flex-order: 8; + order: 8; + } + .order-sm-9 { + -webkit-box-ordinal-group: 10; + -ms-flex-order: 9; + order: 9; + } + .order-sm-10 { + -webkit-box-ordinal-group: 11; + -ms-flex-order: 10; + order: 10; + } + .order-sm-11 { + -webkit-box-ordinal-group: 12; + -ms-flex-order: 11; + order: 11; + } + .order-sm-12 { + -webkit-box-ordinal-group: 13; + -ms-flex-order: 12; + order: 12; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333%; + } + .offset-sm-2 { + margin-left: 16.66667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333%; + } + .offset-sm-5 { + margin-left: 41.66667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333%; + } + .offset-sm-8 { + margin-left: 66.66667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333%; + } + .offset-sm-11 { + margin-left: 91.66667%; + } +} + +@media (min-width: 768px) { + .col-md { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-md-auto { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-md-1 { + -webkit-box-flex: 0; + -ms-flex: 0 0 8.33333%; + flex: 0 0 8.33333%; + max-width: 8.33333%; + } + .col-md-2 { + -webkit-box-flex: 0; + -ms-flex: 0 0 16.66667%; + flex: 0 0 16.66667%; + max-width: 16.66667%; + } + .col-md-3 { + -webkit-box-flex: 0; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-md-4 { + -webkit-box-flex: 0; + -ms-flex: 0 0 33.33333%; + flex: 0 0 33.33333%; + max-width: 33.33333%; + } + .col-md-5 { + -webkit-box-flex: 0; + -ms-flex: 0 0 41.66667%; + flex: 0 0 41.66667%; + max-width: 41.66667%; + } + .col-md-6 { + -webkit-box-flex: 0; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-md-7 { + -webkit-box-flex: 0; + -ms-flex: 0 0 58.33333%; + flex: 0 0 58.33333%; + max-width: 58.33333%; + } + .col-md-8 { + -webkit-box-flex: 0; + -ms-flex: 0 0 66.66667%; + flex: 0 0 66.66667%; + max-width: 66.66667%; + } + .col-md-9 { + -webkit-box-flex: 0; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-md-10 { + -webkit-box-flex: 0; + -ms-flex: 0 0 83.33333%; + flex: 0 0 83.33333%; + max-width: 83.33333%; + } + .col-md-11 { + -webkit-box-flex: 0; + -ms-flex: 0 0 91.66667%; + flex: 0 0 91.66667%; + max-width: 91.66667%; + } + .col-md-12 { + -webkit-box-flex: 0; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-md-first { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1; + } + .order-md-last { + -webkit-box-ordinal-group: 14; + -ms-flex-order: 13; + order: 13; + } + .order-md-0 { + -webkit-box-ordinal-group: 1; + -ms-flex-order: 0; + order: 0; + } + .order-md-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .order-md-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .order-md-3 { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .order-md-4 { + -webkit-box-ordinal-group: 5; + -ms-flex-order: 4; + order: 4; + } + .order-md-5 { + -webkit-box-ordinal-group: 6; + -ms-flex-order: 5; + order: 5; + } + .order-md-6 { + -webkit-box-ordinal-group: 7; + -ms-flex-order: 6; + order: 6; + } + .order-md-7 { + -webkit-box-ordinal-group: 8; + -ms-flex-order: 7; + order: 7; + } + .order-md-8 { + -webkit-box-ordinal-group: 9; + -ms-flex-order: 8; + order: 8; + } + .order-md-9 { + -webkit-box-ordinal-group: 10; + -ms-flex-order: 9; + order: 9; + } + .order-md-10 { + -webkit-box-ordinal-group: 11; + -ms-flex-order: 10; + order: 10; + } + .order-md-11 { + -webkit-box-ordinal-group: 12; + -ms-flex-order: 11; + order: 11; + } + .order-md-12 { + -webkit-box-ordinal-group: 13; + -ms-flex-order: 12; + order: 12; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333%; + } + .offset-md-2 { + margin-left: 16.66667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333%; + } + .offset-md-5 { + margin-left: 41.66667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333%; + } + .offset-md-8 { + margin-left: 66.66667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333%; + } + .offset-md-11 { + margin-left: 91.66667%; + } +} + +@media (min-width: 992px) { + .col-lg { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-lg-auto { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-lg-1 { + -webkit-box-flex: 0; + -ms-flex: 0 0 8.33333%; + flex: 0 0 8.33333%; + max-width: 8.33333%; + } + .col-lg-2 { + -webkit-box-flex: 0; + -ms-flex: 0 0 16.66667%; + flex: 0 0 16.66667%; + max-width: 16.66667%; + } + .col-lg-3 { + -webkit-box-flex: 0; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-lg-4 { + -webkit-box-flex: 0; + -ms-flex: 0 0 33.33333%; + flex: 0 0 33.33333%; + max-width: 33.33333%; + } + .col-lg-5 { + -webkit-box-flex: 0; + -ms-flex: 0 0 41.66667%; + flex: 0 0 41.66667%; + max-width: 41.66667%; + } + .col-lg-6 { + -webkit-box-flex: 0; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-lg-7 { + -webkit-box-flex: 0; + -ms-flex: 0 0 58.33333%; + flex: 0 0 58.33333%; + max-width: 58.33333%; + } + .col-lg-8 { + -webkit-box-flex: 0; + -ms-flex: 0 0 66.66667%; + flex: 0 0 66.66667%; + max-width: 66.66667%; + } + .col-lg-9 { + -webkit-box-flex: 0; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-lg-10 { + -webkit-box-flex: 0; + -ms-flex: 0 0 83.33333%; + flex: 0 0 83.33333%; + max-width: 83.33333%; + } + .col-lg-11 { + -webkit-box-flex: 0; + -ms-flex: 0 0 91.66667%; + flex: 0 0 91.66667%; + max-width: 91.66667%; + } + .col-lg-12 { + -webkit-box-flex: 0; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-lg-first { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1; + } + .order-lg-last { + -webkit-box-ordinal-group: 14; + -ms-flex-order: 13; + order: 13; + } + .order-lg-0 { + -webkit-box-ordinal-group: 1; + -ms-flex-order: 0; + order: 0; + } + .order-lg-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .order-lg-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .order-lg-3 { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .order-lg-4 { + -webkit-box-ordinal-group: 5; + -ms-flex-order: 4; + order: 4; + } + .order-lg-5 { + -webkit-box-ordinal-group: 6; + -ms-flex-order: 5; + order: 5; + } + .order-lg-6 { + -webkit-box-ordinal-group: 7; + -ms-flex-order: 6; + order: 6; + } + .order-lg-7 { + -webkit-box-ordinal-group: 8; + -ms-flex-order: 7; + order: 7; + } + .order-lg-8 { + -webkit-box-ordinal-group: 9; + -ms-flex-order: 8; + order: 8; + } + .order-lg-9 { + -webkit-box-ordinal-group: 10; + -ms-flex-order: 9; + order: 9; + } + .order-lg-10 { + -webkit-box-ordinal-group: 11; + -ms-flex-order: 10; + order: 10; + } + .order-lg-11 { + -webkit-box-ordinal-group: 12; + -ms-flex-order: 11; + order: 11; + } + .order-lg-12 { + -webkit-box-ordinal-group: 13; + -ms-flex-order: 12; + order: 12; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333%; + } + .offset-lg-2 { + margin-left: 16.66667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333%; + } + .offset-lg-5 { + margin-left: 41.66667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333%; + } + .offset-lg-8 { + margin-left: 66.66667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333%; + } + .offset-lg-11 { + margin-left: 91.66667%; + } +} + +@media (min-width: 1200px) { + .col-xl { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-xl-auto { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-xl-1 { + -webkit-box-flex: 0; + -ms-flex: 0 0 8.33333%; + flex: 0 0 8.33333%; + max-width: 8.33333%; + } + .col-xl-2 { + -webkit-box-flex: 0; + -ms-flex: 0 0 16.66667%; + flex: 0 0 16.66667%; + max-width: 16.66667%; + } + .col-xl-3 { + -webkit-box-flex: 0; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-xl-4 { + -webkit-box-flex: 0; + -ms-flex: 0 0 33.33333%; + flex: 0 0 33.33333%; + max-width: 33.33333%; + } + .col-xl-5 { + -webkit-box-flex: 0; + -ms-flex: 0 0 41.66667%; + flex: 0 0 41.66667%; + max-width: 41.66667%; + } + .col-xl-6 { + -webkit-box-flex: 0; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-xl-7 { + -webkit-box-flex: 0; + -ms-flex: 0 0 58.33333%; + flex: 0 0 58.33333%; + max-width: 58.33333%; + } + .col-xl-8 { + -webkit-box-flex: 0; + -ms-flex: 0 0 66.66667%; + flex: 0 0 66.66667%; + max-width: 66.66667%; + } + .col-xl-9 { + -webkit-box-flex: 0; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-xl-10 { + -webkit-box-flex: 0; + -ms-flex: 0 0 83.33333%; + flex: 0 0 83.33333%; + max-width: 83.33333%; + } + .col-xl-11 { + -webkit-box-flex: 0; + -ms-flex: 0 0 91.66667%; + flex: 0 0 91.66667%; + max-width: 91.66667%; + } + .col-xl-12 { + -webkit-box-flex: 0; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-xl-first { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1; + } + .order-xl-last { + -webkit-box-ordinal-group: 14; + -ms-flex-order: 13; + order: 13; + } + .order-xl-0 { + -webkit-box-ordinal-group: 1; + -ms-flex-order: 0; + order: 0; + } + .order-xl-1 { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1; + } + .order-xl-2 { + -webkit-box-ordinal-group: 3; + -ms-flex-order: 2; + order: 2; + } + .order-xl-3 { + -webkit-box-ordinal-group: 4; + -ms-flex-order: 3; + order: 3; + } + .order-xl-4 { + -webkit-box-ordinal-group: 5; + -ms-flex-order: 4; + order: 4; + } + .order-xl-5 { + -webkit-box-ordinal-group: 6; + -ms-flex-order: 5; + order: 5; + } + .order-xl-6 { + -webkit-box-ordinal-group: 7; + -ms-flex-order: 6; + order: 6; + } + .order-xl-7 { + -webkit-box-ordinal-group: 8; + -ms-flex-order: 7; + order: 7; + } + .order-xl-8 { + -webkit-box-ordinal-group: 9; + -ms-flex-order: 8; + order: 8; + } + .order-xl-9 { + -webkit-box-ordinal-group: 10; + -ms-flex-order: 9; + order: 9; + } + .order-xl-10 { + -webkit-box-ordinal-group: 11; + -ms-flex-order: 10; + order: 10; + } + .order-xl-11 { + -webkit-box-ordinal-group: 12; + -ms-flex-order: 11; + order: 11; + } + .order-xl-12 { + -webkit-box-ordinal-group: 13; + -ms-flex-order: 12; + order: 12; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333%; + } + .offset-xl-2 { + margin-left: 16.66667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333%; + } + .offset-xl-5 { + margin-left: 41.66667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333%; + } + .offset-xl-8 { + margin-left: 66.66667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333%; + } + .offset-xl-11 { + margin-left: 91.66667%; + } +} + +.table { + width: 100%; + margin-bottom: 1rem; + color: #212529; +} + +.table th, +.table td { + padding: 0.75rem; + vertical-align: top; + border-top: 1px solid #dee2e6; +} + +.table thead th { + vertical-align: bottom; + border-bottom: 2px solid #dee2e6; +} + +.table tbody + tbody { + border-top: 2px solid #dee2e6; +} + +.table-sm th, +.table-sm td { + padding: 0.3rem; +} + +.table-bordered { + border: 1px solid #dee2e6; +} + +.table-bordered th, +.table-bordered td { + border: 1px solid #dee2e6; +} + +.table-bordered thead th, +.table-bordered thead td { + border-bottom-width: 2px; +} + +.table-borderless th, +.table-borderless td, +.table-borderless thead th, +.table-borderless tbody + tbody { + border: 0; +} + +.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(0, 0, 0, 0.05); +} + +.table-hover tbody tr:hover { + color: #212529; + background-color: rgba(0, 0, 0, 0.075); +} + +.table-primary, +.table-primary > th, +.table-primary > td { + background-color: #b8daff; +} + +.table-primary th, +.table-primary td, +.table-primary thead th, +.table-primary tbody + tbody { + border-color: #7abaff; +} + +.table-hover .table-primary:hover { + background-color: #9fcdff; +} + +.table-hover .table-primary:hover > td, +.table-hover .table-primary:hover > th { + background-color: #9fcdff; +} + +.table-secondary, +.table-secondary > th, +.table-secondary > td { + background-color: #d6d8db; +} + +.table-secondary th, +.table-secondary td, +.table-secondary thead th, +.table-secondary tbody + tbody { + border-color: #b3b7bb; +} + +.table-hover .table-secondary:hover { + background-color: #c8cbcf; +} + +.table-hover .table-secondary:hover > td, +.table-hover .table-secondary:hover > th { + background-color: #c8cbcf; +} + +.table-success, +.table-success > th, +.table-success > td { + background-color: #c3e6cb; +} + +.table-success th, +.table-success td, +.table-success thead th, +.table-success tbody + tbody { + border-color: #8fd19e; +} + +.table-hover .table-success:hover { + background-color: #b1dfbb; +} + +.table-hover .table-success:hover > td, +.table-hover .table-success:hover > th { + background-color: #b1dfbb; +} + +.table-info, +.table-info > th, +.table-info > td { + background-color: #bee5eb; +} + +.table-info th, +.table-info td, +.table-info thead th, +.table-info tbody + tbody { + border-color: #86cfda; +} + +.table-hover .table-info:hover { + background-color: #abdde5; +} + +.table-hover .table-info:hover > td, +.table-hover .table-info:hover > th { + background-color: #abdde5; +} + +.table-warning, +.table-warning > th, +.table-warning > td { + background-color: #ffeeba; +} + +.table-warning th, +.table-warning td, +.table-warning thead th, +.table-warning tbody + tbody { + border-color: #ffdf7e; +} + +.table-hover .table-warning:hover { + background-color: #ffe8a1; +} + +.table-hover .table-warning:hover > td, +.table-hover .table-warning:hover > th { + background-color: #ffe8a1; +} + +.table-danger, +.table-danger > th, +.table-danger > td { + background-color: #f5c6cb; +} + +.table-danger th, +.table-danger td, +.table-danger thead th, +.table-danger tbody + tbody { + border-color: #ed969e; +} + +.table-hover .table-danger:hover { + background-color: #f1b0b7; +} + +.table-hover .table-danger:hover > td, +.table-hover .table-danger:hover > th { + background-color: #f1b0b7; +} + +.table-light, +.table-light > th, +.table-light > td { + background-color: #fdfdfe; +} + +.table-light th, +.table-light td, +.table-light thead th, +.table-light tbody + tbody { + border-color: #fbfcfc; +} + +.table-hover .table-light:hover { + background-color: #ececf6; +} + +.table-hover .table-light:hover > td, +.table-hover .table-light:hover > th { + background-color: #ececf6; +} + +.table-dark, +.table-dark > th, +.table-dark > td { + background-color: #c6c8ca; +} + +.table-dark th, +.table-dark td, +.table-dark thead th, +.table-dark tbody + tbody { + border-color: #95999c; +} + +.table-hover .table-dark:hover { + background-color: #b9bbbe; +} + +.table-hover .table-dark:hover > td, +.table-hover .table-dark:hover > th { + background-color: #b9bbbe; +} + +.table-active, +.table-active > th, +.table-active > td { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover > td, +.table-hover .table-active:hover > th { + background-color: rgba(0, 0, 0, 0.075); +} + +.table .thead-dark th { + color: #fff; + background-color: #343a40; + border-color: #454d55; +} + +.table .thead-light th { + color: #495057; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.table-dark { + color: #fff; + background-color: #343a40; +} + +.table-dark th, +.table-dark td, +.table-dark thead th { + border-color: #454d55; +} + +.table-dark.table-bordered { + border: 0; +} + +.table-dark.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(255, 255, 255, 0.05); +} + +.table-dark.table-hover tbody tr:hover { + color: #fff; + background-color: rgba(255, 255, 255, 0.075); +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-sm > .table-bordered { + border: 0; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-md > .table-bordered { + border: 0; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-lg > .table-bordered { + border: 0; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-xl > .table-bordered { + border: 0; + } +} + +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.table-responsive > .table-bordered { + border: 0; +} + +.form-control { + display: block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + -webkit-transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control { + -webkit-transition: none; + transition: none; + } +} + +.form-control::-ms-expand { + background-color: transparent; + border: 0; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.form-control::-webkit-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-moz-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +select.form-control:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.form-control-file, +.form-control-range { + display: block; + width: 100%; +} + +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 1.25rem; + line-height: 1.5; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + font-size: 0.875rem; + line-height: 1.5; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding-top: 0.375rem; + padding-bottom: 0.375rem; + margin-bottom: 0; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.form-control-lg { + height: calc(1.5em + 1rem + 2px); + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +select.form-control[size], select.form-control[multiple] { + height: auto; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 1rem; +} + +.form-text { + display: block; + margin-top: 0.25rem; +} + +.form-row { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -5px; + margin-left: -5px; +} + +.form-row > .col, +.form-row > [class*="col-"] { + padding-right: 5px; + padding-left: 5px; +} + +.form-check { + position: relative; + display: block; + padding-left: 1.25rem; +} + +.form-check-input { + position: absolute; + margin-top: 0.3rem; + margin-left: -1.25rem; +} + +.form-check-input:disabled ~ .form-check-label { + color: #6c757d; +} + +.form-check-label { + margin-bottom: 0; +} + +.form-check-inline { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding-left: 0; + margin-right: 0.75rem; +} + +.form-check-inline .form-check-input { + position: static; + margin-top: 0; + margin-right: 0.3125rem; + margin-left: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #28a745; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: center right calc(0.375em + 0.1875rem); + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #28a745; + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-control:valid ~ .valid-feedback, +.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback, +.form-control.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:valid, .custom-select.is-valid { + border-color: #28a745; + padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus { + border-color: #28a745; + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-select:valid ~ .valid-feedback, +.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback, +.custom-select.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control-file:valid ~ .valid-feedback, +.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback, +.form-control-file.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #28a745; +} + +.was-validated .form-check-input:valid ~ .valid-feedback, +.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback, +.form-check-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label { + color: #28a745; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-control-input:valid ~ .valid-feedback, +.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback, +.custom-control-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before { + border-color: #34ce57; + background-color: #34ce57; +} + +.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before { + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid ~ .valid-feedback, +.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback, +.custom-file-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label { + border-color: #28a745; + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"); + background-repeat: no-repeat; + background-position: center right calc(0.375em + 0.1875rem); + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-control:invalid ~ .invalid-feedback, +.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback, +.form-control.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:invalid, .custom-select.is-invalid { + border-color: #dc3545; + padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus { + border-color: #dc3545; + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-select:invalid ~ .invalid-feedback, +.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback, +.custom-select.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control-file:invalid ~ .invalid-feedback, +.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback, +.form-control-file.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.was-validated .form-check-input:invalid ~ .invalid-feedback, +.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback, +.form-check-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label { + color: #dc3545; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-control-input:invalid ~ .invalid-feedback, +.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback, +.custom-control-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before { + border-color: #e4606d; + background-color: #e4606d; +} + +.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before { + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid ~ .invalid-feedback, +.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback, +.custom-file-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label { + border-color: #dc3545; + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.form-inline { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.form-inline .form-check { + width: 100%; +} + +@media (min-width: 576px) { + .form-inline label { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 0; + } + .form-inline .form-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 0; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-plaintext { + display: inline-block; + } + .form-inline .input-group, + .form-inline .custom-select { + width: auto; + } + .form-inline .form-check { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + width: auto; + padding-left: 0; + } + .form-inline .form-check-input { + position: relative; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-top: 0; + margin-right: 0.25rem; + margin-left: 0; + } + .form-inline .custom-control { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } + .form-inline .custom-control-label { + margin-bottom: 0; + } +} + +.btn { + display: inline-block; + font-weight: 400; + color: #212529; + text-align: center; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.375rem 0.75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: 0.25rem; + -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .btn { + -webkit-transition: none; + transition: none; + } +} + +.btn:hover { + color: #212529; + text-decoration: none; +} + +.btn:focus, .btn.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.btn.disabled, .btn:disabled { + opacity: 0.65; +} + +a.btn.disabled, +fieldset:disabled a.btn { + pointer-events: none; +} + +.btn-primary { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:hover { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; +} + +.btn-primary:focus, .btn-primary.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-primary.disabled, .btn-primary:disabled { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, +.show > .btn-primary.dropdown-toggle { + color: #fff; + background-color: #0062cc; + border-color: #005cbf; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-primary.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5a6268; + border-color: #545b62; +} + +.btn-secondary:focus, .btn-secondary.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary.disabled, .btn-secondary:disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, +.show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #545b62; + border-color: #4e555b; +} + +.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-secondary.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-success { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #fff; + background-color: #218838; + border-color: #1e7e34; +} + +.btn-success:focus, .btn-success.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-success.disabled, .btn-success:disabled { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, +.show > .btn-success.dropdown-toggle { + color: #fff; + background-color: #1e7e34; + border-color: #1c7430; +} + +.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-success.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-info { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #fff; + background-color: #138496; + border-color: #117a8b; +} + +.btn-info:focus, .btn-info.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-info.disabled, .btn-info:disabled { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, +.show > .btn-info.dropdown-toggle { + color: #fff; + background-color: #117a8b; + border-color: #10707f; +} + +.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-info.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-warning { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; +} + +.btn-warning:focus, .btn-warning.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-warning.disabled, .btn-warning:disabled { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, +.show > .btn-warning.dropdown-toggle { + color: #212529; + background-color: #d39e00; + border-color: #c69500; +} + +.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-warning.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #c82333; + border-color: #bd2130; +} + +.btn-danger:focus, .btn-danger.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger.disabled, .btn-danger:disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, +.show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #bd2130; + border-color: #b21f2d; +} + +.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-danger.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-light { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; +} + +.btn-light:focus, .btn-light.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-light.disabled, .btn-light:disabled { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, +.show > .btn-light.dropdown-toggle { + color: #212529; + background-color: #dae0e5; + border-color: #d3d9df; +} + +.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-light.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-dark { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:hover { + color: #fff; + background-color: #23272b; + border-color: #1d2124; +} + +.btn-dark:focus, .btn-dark.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-dark.disabled, .btn-dark:disabled { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, +.show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1d2124; + border-color: #171a1d; +} + +.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-dark.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-outline-primary { + color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:focus, .btn-outline-primary.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-primary.disabled, .btn-outline-primary:disabled { + color: #007bff; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, +.show > .btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-primary.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:focus, .btn-outline-secondary.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, +.show > .btn-outline-secondary.dropdown-toggle { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-secondary.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:focus, .btn-outline-success.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success.disabled, .btn-outline-success:disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, +.show > .btn-outline-success.dropdown-toggle { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-success.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:focus, .btn-outline-info.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info.disabled, .btn-outline-info:disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, +.show > .btn-outline-info.dropdown-toggle { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-info.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:focus, .btn-outline-warning.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning.disabled, .btn-outline-warning:disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, +.show > .btn-outline-warning.dropdown-toggle { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-warning.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:focus, .btn-outline-danger.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger.disabled, .btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, +.show > .btn-outline-danger.dropdown-toggle { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-danger.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:focus, .btn-outline-light.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light.disabled, .btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, +.show > .btn-outline-light.dropdown-toggle { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-light.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-dark { + color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:focus, .btn-outline-dark.focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-outline-dark.disabled, .btn-outline-dark:disabled { + color: #343a40; + background-color: transparent; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, +.show > .btn-outline-dark.dropdown-toggle { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-dark.dropdown-toggle:focus { + -webkit-box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-link { + font-weight: 400; + color: #007bff; + text-decoration: none; +} + +.btn-link:hover { + color: #0056b3; + text-decoration: underline; +} + +.btn-link:focus, .btn-link.focus { + text-decoration: underline; + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-link:disabled, .btn-link.disabled { + color: #6c757d; + pointer-events: none; +} + +.btn-lg, .btn-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.btn-block { + display: block; + width: 100%; +} + +.btn-block + .btn-block { + margin-top: 0.5rem; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + -webkit-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +@media (prefers-reduced-motion: reduce) { + .fade { + -webkit-transition: none; + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + -webkit-transition: none; + transition: none; + } +} + +.dropup, +.dropright, +.dropdown, +.dropleft { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0.125rem 0 0; + font-size: 1rem; + color: #212529; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; +} + +.dropdown-menu-left { + right: auto; + left: 0; +} + +.dropdown-menu-right { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-left { + right: auto; + left: 0; + } + .dropdown-menu-sm-right { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-left { + right: auto; + left: 0; + } + .dropdown-menu-md-right { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-left { + right: auto; + left: 0; + } + .dropdown-menu-lg-right { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-left { + right: auto; + left: 0; + } + .dropdown-menu-xl-right { + right: 0; + left: auto; + } +} + +.dropup .dropdown-menu { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-menu { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropright .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropright .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-toggle::after { + vertical-align: 0; +} + +.dropleft .dropdown-menu { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropleft .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropleft .dropdown-toggle::after { + display: none; +} + +.dropleft .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropleft .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] { + right: auto; + bottom: auto; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid #e9ecef; +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.25rem 1.5rem; + clear: both; + font-weight: 400; + color: #212529; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:hover, .dropdown-item:focus { + color: #16181b; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #007bff; +} + +.dropdown-item.disabled, .dropdown-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.875rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.25rem 1.5rem; + color: #212529; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover { + z-index: 1; +} + +.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropright .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.btn-group-toggle > .btn, +.btn-group-toggle > .btn-group > .btn { + margin-bottom: 0; +} + +.btn-group-toggle > .btn input[type="radio"], +.btn-group-toggle > .btn input[type="checkbox"], +.btn-group-toggle > .btn-group > .btn input[type="radio"], +.btn-group-toggle > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.input-group { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + width: 100%; +} + +.input-group > .form-control, +.input-group > .form-control-plaintext, +.input-group > .custom-select, +.input-group > .custom-file { + position: relative; + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + width: 1%; + margin-bottom: 0; +} + +.input-group > .form-control + .form-control, +.input-group > .form-control + .custom-select, +.input-group > .form-control + .custom-file, +.input-group > .form-control-plaintext + .form-control, +.input-group > .form-control-plaintext + .custom-select, +.input-group > .form-control-plaintext + .custom-file, +.input-group > .custom-select + .form-control, +.input-group > .custom-select + .custom-select, +.input-group > .custom-select + .custom-file, +.input-group > .custom-file + .form-control, +.input-group > .custom-file + .custom-select, +.input-group > .custom-file + .custom-file { + margin-left: -1px; +} + +.input-group > .form-control:focus, +.input-group > .custom-select:focus, +.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label { + z-index: 3; +} + +.input-group > .custom-file .custom-file-input:focus { + z-index: 4; +} + +.input-group > .form-control:not(:last-child), +.input-group > .custom-select:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .form-control:not(:first-child), +.input-group > .custom-select:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group > .custom-file { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.input-group > .custom-file:not(:last-child) .custom-file-label, +.input-group > .custom-file:not(:last-child) .custom-file-label::after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .custom-file:not(:first-child) .custom-file-label { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group-prepend, +.input-group-append { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.input-group-prepend .btn, +.input-group-append .btn { + position: relative; + z-index: 2; +} + +.input-group-prepend .btn:focus, +.input-group-append .btn:focus { + z-index: 3; +} + +.input-group-prepend .btn + .btn, +.input-group-prepend .btn + .input-group-text, +.input-group-prepend .input-group-text + .input-group-text, +.input-group-prepend .input-group-text + .btn, +.input-group-append .btn + .btn, +.input-group-append .btn + .input-group-text, +.input-group-append .input-group-text + .input-group-text, +.input-group-append .input-group-text + .btn { + margin-left: -1px; +} + +.input-group-prepend { + margin-right: -1px; +} + +.input-group-append { + margin-left: -1px; +} + +.input-group-text { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0.375rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.input-group-text input[type="radio"], +.input-group-text input[type="checkbox"] { + margin-top: 0; +} + +.input-group-lg > .form-control:not(textarea), +.input-group-lg > .custom-select { + height: calc(1.5em + 1rem + 2px); +} + +.input-group-lg > .form-control, +.input-group-lg > .custom-select, +.input-group-lg > .input-group-prepend > .input-group-text, +.input-group-lg > .input-group-append > .input-group-text, +.input-group-lg > .input-group-prepend > .btn, +.input-group-lg > .input-group-append > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.input-group-sm > .form-control:not(textarea), +.input-group-sm > .custom-select { + height: calc(1.5em + 0.5rem + 2px); +} + +.input-group-sm > .form-control, +.input-group-sm > .custom-select, +.input-group-sm > .input-group-prepend > .input-group-text, +.input-group-sm > .input-group-append > .input-group-text, +.input-group-sm > .input-group-prepend > .btn, +.input-group-sm > .input-group-append > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.input-group-lg > .custom-select, +.input-group-sm > .custom-select { + padding-right: 1.75rem; +} + +.input-group > .input-group-prepend > .btn, +.input-group > .input-group-prepend > .input-group-text, +.input-group > .input-group-append:not(:last-child) > .btn, +.input-group > .input-group-append:not(:last-child) > .input-group-text, +.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .input-group-append > .btn, +.input-group > .input-group-append > .input-group-text, +.input-group > .input-group-prepend:not(:first-child) > .btn, +.input-group > .input-group-prepend:not(:first-child) > .input-group-text, +.input-group > .input-group-prepend:first-child > .btn:not(:first-child), +.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.custom-control { + position: relative; + display: block; + min-height: 1.5rem; + padding-left: 1.5rem; +} + +.custom-control-inline { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + margin-right: 1rem; +} + +.custom-control-input { + position: absolute; + z-index: -1; + opacity: 0; +} + +.custom-control-input:checked ~ .custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.custom-control-input:focus ~ .custom-control-label::before { + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-control-input:focus:not(:checked) ~ .custom-control-label::before { + border-color: #80bdff; +} + +.custom-control-input:not(:disabled):active ~ .custom-control-label::before { + color: #fff; + background-color: #b3d7ff; + border-color: #b3d7ff; +} + +.custom-control-input:disabled ~ .custom-control-label { + color: #6c757d; +} + +.custom-control-input:disabled ~ .custom-control-label::before { + background-color: #e9ecef; +} + +.custom-control-label { + position: relative; + margin-bottom: 0; + vertical-align: top; +} + +.custom-control-label::before { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + pointer-events: none; + content: ""; + background-color: #fff; + border: #adb5bd solid 1px; +} + +.custom-control-label::after { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + content: ""; + background: no-repeat 50% / 50% 50%; +} + +.custom-checkbox .custom-control-label::before { + border-radius: 0.25rem; +} + +.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before { + border-color: #007bff; + background-color: #007bff; +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-radio .custom-control-label::before { + border-radius: 50%; +} + +.custom-radio .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-switch { + padding-left: 2.25rem; +} + +.custom-switch .custom-control-label::before { + left: -2.25rem; + width: 1.75rem; + pointer-events: all; + border-radius: 0.5rem; +} + +.custom-switch .custom-control-label::after { + top: calc(0.25rem + 2px); + left: calc(-2.25rem + 2px); + width: calc(1rem - 4px); + height: calc(1rem - 4px); + background-color: #adb5bd; + border-radius: 0.5rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .custom-switch .custom-control-label::after { + -webkit-transition: none; + transition: none; + } +} + +.custom-switch .custom-control-input:checked ~ .custom-control-label::after { + background-color: #fff; + -webkit-transform: translateX(0.75rem); + transform: translateX(0.75rem); +} + +.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-select { + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 1.75rem 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + vertical-align: middle; + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-select:focus { + border-color: #80bdff; + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-select:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.custom-select[multiple], .custom-select[size]:not([size="1"]) { + height: auto; + padding-right: 0.75rem; + background-image: none; +} + +.custom-select:disabled { + color: #6c757d; + background-color: #e9ecef; +} + +.custom-select::-ms-expand { + display: none; +} + +.custom-select-sm { + height: calc(1.5em + 0.5rem + 2px); + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; +} + +.custom-select-lg { + height: calc(1.5em + 1rem + 2px); + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; +} + +.custom-file { + position: relative; + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin-bottom: 0; +} + +.custom-file-input { + position: relative; + z-index: 2; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin: 0; + opacity: 0; +} + +.custom-file-input:focus ~ .custom-file-label { + border-color: #80bdff; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-file-input:disabled ~ .custom-file-label { + background-color: #e9ecef; +} + +.custom-file-input:lang(en) ~ .custom-file-label::after { + content: "Browse"; +} + +.custom-file-input ~ .custom-file-label[data-browse]::after { + content: attr(data-browse); +} + +.custom-file-label { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.custom-file-label::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + z-index: 3; + display: block; + height: calc(1.5em + 0.75rem); + padding: 0.375rem 0.75rem; + line-height: 1.5; + color: #495057; + content: "Browse"; + background-color: #e9ecef; + border-left: inherit; + border-radius: 0 0.25rem 0.25rem 0; +} + +.custom-range { + width: 100%; + height: calc(1rem + 0.4rem); + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-range:focus { + outline: none; +} + +.custom-range:focus::-webkit-slider-thumb { + -webkit-box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-ms-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range::-moz-focus-outer { + border: 0; +} + +.custom-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } +} + +.custom-range::-webkit-slider-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + -moz-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-moz-range-thumb { + -webkit-transition: none; + transition: none; + } +} + +.custom-range::-moz-range-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-ms-thumb { + width: 1rem; + height: 1rem; + margin-top: 0; + margin-right: 0.2rem; + margin-left: 0.2rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-ms-thumb { + -webkit-transition: none; + transition: none; + } +} + +.custom-range::-ms-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-ms-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: transparent; + border-color: transparent; + border-width: 0.5rem; +} + +.custom-range::-ms-fill-lower { + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range::-ms-fill-upper { + margin-right: 15px; + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-webkit-slider-runnable-track { + cursor: default; +} + +.custom-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-moz-range-track { + cursor: default; +} + +.custom-range:disabled::-ms-thumb { + background-color: #adb5bd; +} + +.custom-control-label::before, +.custom-file-label, +.custom-select { + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .custom-control-label::before, + .custom-file-label, + .custom-select { + -webkit-transition: none; + transition: none; + } +} + +.nav { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; +} + +.nav-link:hover, .nav-link:focus { + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-item { + margin-bottom: -1px; +} + +.nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + border-radius: 0.25rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #fff; + background-color: #007bff; +} + +.nav-fill .nav-item { + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + text-align: center; +} + +.nav-justified .nav-item { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + text-align: center; +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.navbar { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0.5rem 1rem; +} + +.navbar > .container, +.navbar > .container-fluid { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.navbar-brand { + display: inline-block; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; +} + +.navbar-brand:hover, .navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; + float: none; +} + +.navbar-text { + display: inline-block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.navbar-toggler:hover, .navbar-toggler:focus { + text-decoration: none; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + content: ""; + background: no-repeat center center; + background-size: 100% 100%; +} + +@media (max-width: 575.98px) { + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 576px) { + .navbar-expand-sm { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-sm .navbar-collapse { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } +} + +@media (max-width: 767.98px) { + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-md .navbar-collapse { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } +} + +@media (max-width: 991.98px) { + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-lg .navbar-collapse { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } +} + +@media (max-width: 1199.98px) { + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-xl .navbar-collapse { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } +} + +.navbar-expand { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid { + padding-right: 0; + padding-left: 0; +} + +.navbar-expand .navbar-nav { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; +} + +.navbar-expand .navbar-collapse { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link, +.navbar-light .navbar-nav .active > .nav-link, +.navbar-light .navbar-nav .nav-link.show, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-text a { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link, +.navbar-dark .navbar-nav .active > .nav-link, +.navbar-dark .navbar-nav .nav-link.show, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-text a { + color: #fff; +} + +.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; +} + +.card > hr { + margin-right: 0; + margin-left: 0; +} + +.card > .list-group:first-child .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-body { + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1.25rem; +} + +.card-title { + margin-bottom: 0.75rem; +} + +.card-subtitle { + margin-top: -0.375rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link + .card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 0.75rem 1.25rem; + margin-bottom: 0; + background-color: rgba(0, 0, 0, 0.03); + border-bottom: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-header:first-child { + border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; +} + +.card-header + .list-group .list-group-item:first-child { + border-top: 0; +} + +.card-footer { + padding: 0.75rem 1.25rem; + background-color: rgba(0, 0, 0, 0.03); + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-footer:last-child { + border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -0.75rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1.25rem; +} + +.card-img { + width: 100%; + border-radius: calc(0.25rem - 1px); +} + +.card-img-top { + width: 100%; + border-top-left-radius: calc(0.25rem - 1px); + border-top-right-radius: calc(0.25rem - 1px); +} + +.card-img-bottom { + width: 100%; + border-bottom-right-radius: calc(0.25rem - 1px); + border-bottom-left-radius: calc(0.25rem - 1px); +} + +.card-deck { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.card-deck .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-deck { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + margin-right: -15px; + margin-left: -15px; + } + .card-deck .card { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -ms-flex: 1 0 0%; + flex: 1 0 0%; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + margin-right: 15px; + margin-bottom: 0; + margin-left: 15px; + } +} + +.card-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.card-group > .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-group { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } + .card-group > .card { + -webkit-box-flex: 1; + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.card-columns .card { + margin-bottom: 0.75rem; +} + +@media (min-width: 576px) { + .card-columns { + -webkit-column-count: 3; + -moz-column-count: 3; + column-count: 3; + -webkit-column-gap: 1.25rem; + -moz-column-gap: 1.25rem; + column-gap: 1.25rem; + orphans: 1; + widows: 1; + } + .card-columns .card { + display: inline-block; + width: 100%; + } +} + +.accordion > .card { + overflow: hidden; +} + +.accordion > .card:not(:first-of-type) .card-header:first-child { + border-radius: 0; +} + +.accordion > .card:not(:first-of-type):not(:last-of-type) { + border-bottom: 0; + border-radius: 0; +} + +.accordion > .card:first-of-type { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.accordion > .card:last-of-type { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.accordion > .card .card-header { + margin-bottom: -1px; +} + +.breadcrumb { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding: 0.75rem 1rem; + margin-bottom: 1rem; + list-style: none; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item + .breadcrumb-item::before { + display: inline-block; + padding-right: 0.5rem; + color: #6c757d; + content: "/"; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: underline; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: none; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.pagination { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding-left: 0; + list-style: none; + border-radius: 0.25rem; +} + +.page-link { + position: relative; + display: block; + padding: 0.5rem 0.75rem; + margin-left: -1px; + line-height: 1.25; + color: #007bff; + background-color: #fff; + border: 1px solid #dee2e6; +} + +.page-link:hover { + z-index: 2; + color: #0056b3; + text-decoration: none; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-link:focus { + z-index: 2; + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.page-item:first-child .page-link { + margin-left: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.page-item:last-child .page-link { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.page-item.active .page-link { + z-index: 1; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.page-item.disabled .page-link { + color: #6c757d; + pointer-events: none; + cursor: auto; + background-color: #fff; + border-color: #dee2e6; +} + +.pagination-lg .page-link { + padding: 0.75rem 1.5rem; + font-size: 1.25rem; + line-height: 1.5; +} + +.pagination-lg .page-item:first-child .page-link { + border-top-left-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.pagination-lg .page-item:last-child .page-link { + border-top-right-radius: 0.3rem; + border-bottom-right-radius: 0.3rem; +} + +.pagination-sm .page-link { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; +} + +.pagination-sm .page-item:first-child .page-link { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.pagination-sm .page-item:last-child .page-link { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; +} + +.badge { + display: inline-block; + padding: 0.25em 0.4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25rem; + -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .badge { + -webkit-transition: none; + transition: none; + } +} + +a.badge:hover, a.badge:focus { + text-decoration: none; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.badge-pill { + padding-right: 0.6em; + padding-left: 0.6em; + border-radius: 10rem; +} + +.badge-primary { + color: #fff; + background-color: #007bff; +} + +a.badge-primary:hover, a.badge-primary:focus { + color: #fff; + background-color: #0062cc; +} + +a.badge-primary:focus, a.badge-primary.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.badge-secondary { + color: #fff; + background-color: #6c757d; +} + +a.badge-secondary:hover, a.badge-secondary:focus { + color: #fff; + background-color: #545b62; +} + +a.badge-secondary:focus, a.badge-secondary.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.badge-success { + color: #fff; + background-color: #28a745; +} + +a.badge-success:hover, a.badge-success:focus { + color: #fff; + background-color: #1e7e34; +} + +a.badge-success:focus, a.badge-success.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.badge-info { + color: #fff; + background-color: #17a2b8; +} + +a.badge-info:hover, a.badge-info:focus { + color: #fff; + background-color: #117a8b; +} + +a.badge-info:focus, a.badge-info.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +a.badge-warning:hover, a.badge-warning:focus { + color: #212529; + background-color: #d39e00; +} + +a.badge-warning:focus, a.badge-warning.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.badge-danger { + color: #fff; + background-color: #dc3545; +} + +a.badge-danger:hover, a.badge-danger:focus { + color: #fff; + background-color: #bd2130; +} + +a.badge-danger:focus, a.badge-danger.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.badge-light { + color: #212529; + background-color: #f8f9fa; +} + +a.badge-light:hover, a.badge-light:focus { + color: #212529; + background-color: #dae0e5; +} + +a.badge-light:focus, a.badge-light.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.badge-dark { + color: #fff; + background-color: #343a40; +} + +a.badge-dark:hover, a.badge-dark:focus { + color: #fff; + background-color: #1d2124; +} + +a.badge-dark:focus, a.badge-dark.focus { + outline: 0; + -webkit-box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.jumbotron { + padding: 2rem 1rem; + margin-bottom: 2rem; + background-color: #e9ecef; + border-radius: 0.3rem; +} + +@media (min-width: 576px) { + .jumbotron { + padding: 4rem 2rem; + } +} + +.jumbotron-fluid { + padding-right: 0; + padding-left: 0; + border-radius: 0; +} + +.alert { + position: relative; + padding: 0.75rem 1.25rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; +} + +.alert-dismissible { + padding-right: 4rem; +} + +.alert-dismissible .close { + position: absolute; + top: 0; + right: 0; + padding: 0.75rem 1.25rem; + color: inherit; +} + +.alert-primary { + color: #004085; + background-color: #cce5ff; + border-color: #b8daff; +} + +.alert-primary hr { + border-top-color: #9fcdff; +} + +.alert-primary .alert-link { + color: #002752; +} + +.alert-secondary { + color: #383d41; + background-color: #e2e3e5; + border-color: #d6d8db; +} + +.alert-secondary hr { + border-top-color: #c8cbcf; +} + +.alert-secondary .alert-link { + color: #202326; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-success hr { + border-top-color: #b1dfbb; +} + +.alert-success .alert-link { + color: #0b2e13; +} + +.alert-info { + color: #0c5460; + background-color: #d1ecf1; + border-color: #bee5eb; +} + +.alert-info hr { + border-top-color: #abdde5; +} + +.alert-info .alert-link { + color: #062c33; +} + +.alert-warning { + color: #856404; + background-color: #fff3cd; + border-color: #ffeeba; +} + +.alert-warning hr { + border-top-color: #ffe8a1; +} + +.alert-warning .alert-link { + color: #533f03; +} + +.alert-danger { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; +} + +.alert-danger hr { + border-top-color: #f1b0b7; +} + +.alert-danger .alert-link { + color: #491217; +} + +.alert-light { + color: #818182; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light hr { + border-top-color: #ececf6; +} + +.alert-light .alert-link { + color: #686868; +} + +.alert-dark { + color: #1b1e21; + background-color: #d6d8d9; + border-color: #c6c8ca; +} + +.alert-dark hr { + border-top-color: #b9bbbe; +} + +.alert-dark .alert-link { + color: #040505; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +.progress { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + height: 1rem; + overflow: hidden; + font-size: 0.75rem; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.progress-bar { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #007bff; + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar { + -webkit-transition: none; + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 1rem 1rem; +} + +.progress-bar-animated { + -webkit-animation: progress-bar-stripes 1s linear infinite; + animation: progress-bar-stripes 1s linear infinite; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + -webkit-animation: none; + animation: none; + } +} + +.media { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; +} + +.media-body { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.list-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #212529; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.list-group-horizontal { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.list-group-horizontal .list-group-item { + margin-right: -1px; + margin-bottom: 0; +} + +.list-group-horizontal .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; +} + +.list-group-horizontal .list-group-item:last-child { + margin-right: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0; +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-sm .list-group-item { + margin-right: -1px; + margin-bottom: 0; + } + .list-group-horizontal-sm .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-sm .list-group-item:last-child { + margin-right: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } +} + +@media (min-width: 768px) { + .list-group-horizontal-md { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-md .list-group-item { + margin-right: -1px; + margin-bottom: 0; + } + .list-group-horizontal-md .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-md .list-group-item:last-child { + margin-right: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } +} + +@media (min-width: 992px) { + .list-group-horizontal-lg { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-lg .list-group-item { + margin-right: -1px; + margin-bottom: 0; + } + .list-group-horizontal-lg .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-lg .list-group-item:last-child { + margin-right: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } +} + +@media (min-width: 1200px) { + .list-group-horizontal-xl { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-xl .list-group-item { + margin-right: -1px; + margin-bottom: 0; + } + .list-group-horizontal-xl .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xl .list-group-item:last-child { + margin-right: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } +} + +.list-group-flush .list-group-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} + +.list-group-flush .list-group-item:last-child { + margin-bottom: -1px; +} + +.list-group-flush:first-child .list-group-item:first-child { + border-top: 0; +} + +.list-group-flush:last-child .list-group-item:last-child { + margin-bottom: 0; + border-bottom: 0; +} + +.list-group-item-primary { + color: #004085; + background-color: #b8daff; +} + +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #004085; + background-color: #9fcdff; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #004085; + border-color: #004085; +} + +.list-group-item-secondary { + color: #383d41; + background-color: #d6d8db; +} + +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #383d41; + background-color: #c8cbcf; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #383d41; + border-color: #383d41; +} + +.list-group-item-success { + color: #155724; + background-color: #c3e6cb; +} + +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #155724; + background-color: #b1dfbb; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #155724; + border-color: #155724; +} + +.list-group-item-info { + color: #0c5460; + background-color: #bee5eb; +} + +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #0c5460; + background-color: #abdde5; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0c5460; + border-color: #0c5460; +} + +.list-group-item-warning { + color: #856404; + background-color: #ffeeba; +} + +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #856404; + background-color: #ffe8a1; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #856404; + border-color: #856404; +} + +.list-group-item-danger { + color: #721c24; + background-color: #f5c6cb; +} + +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #721c24; + background-color: #f1b0b7; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #721c24; + border-color: #721c24; +} + +.list-group-item-light { + color: #818182; + background-color: #fdfdfe; +} + +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #818182; + background-color: #ececf6; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #818182; + border-color: #818182; +} + +.list-group-item-dark { + color: #1b1e21; + background-color: #c6c8ca; +} + +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #1b1e21; + background-color: #b9bbbe; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #1b1e21; + border-color: #1b1e21; +} + +.close { + float: right; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + opacity: .5; +} + +.close:hover { + color: #000; + text-decoration: none; +} + +.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus { + opacity: .75; +} + +button.close { + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +a.close.disabled { + pointer-events: none; +} + +.toast { + max-width: 350px; + overflow: hidden; + font-size: 0.875rem; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.1); + -webkit-box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1); + box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + opacity: 0; + border-radius: 0.25rem; +} + +.toast:not(:last-child) { + margin-bottom: 0.75rem; +} + +.toast.showing { + opacity: 1; +} + +.toast.show { + display: block; + opacity: 1; +} + +.toast.hide { + display: none; +} + +.toast-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0.25rem 0.75rem; + color: #6c757d; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.toast-body { + padding: 0.75rem; +} + +.modal-open { + overflow: hidden; +} + +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + display: none; + width: 100%; + height: 100%; + overflow: hidden; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform 0.3s ease-out; + transition: -webkit-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out; + -webkit-transform: translate(0, -50px); + transform: translate(0, -50px); +} + +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + -webkit-transition: none; + transition: none; + } +} + +.modal.show .modal-dialog { + -webkit-transform: none; + transform: none; +} + +.modal-dialog-scrollable { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + max-height: calc(100% - 1rem); +} + +.modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 1rem); + overflow: hidden; +} + +.modal-dialog-scrollable .modal-header, +.modal-dialog-scrollable .modal-footer { + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - 1rem); +} + +.modal-dialog-centered::before { + display: block; + height: calc(100vh - 1rem); + content: ""; +} + +.modal-dialog-centered.modal-dialog-scrollable { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + height: 100%; +} + +.modal-dialog-centered.modal-dialog-scrollable .modal-content { + max-height: none; +} + +.modal-dialog-centered.modal-dialog-scrollable::before { + content: none; +} + +.modal-content { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; +} + +.modal-header .close { + padding: 1rem 1rem; + margin: -1rem -1rem -1rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + padding: 1rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.modal-footer > :not(:first-child) { + margin-left: .25rem; +} + +.modal-footer > :not(:last-child) { + margin-right: .25rem; +} + +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto; + } + .modal-dialog-scrollable { + max-height: calc(100% - 3.5rem); + } + .modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 3.5rem); + } + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + .modal-dialog-centered::before { + height: calc(100vh - 3.5rem); + } + .modal-sm { + max-width: 300px; + } +} + +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + max-width: 800px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.tooltip { + position: absolute; + z-index: 1070; + display: block; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + opacity: 0; +} + +.tooltip.show { + opacity: 0.9; +} + +.tooltip .arrow { + position: absolute; + display: block; + width: 0.8rem; + height: 0.4rem; +} + +.tooltip .arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] { + padding: 0.4rem 0; +} + +.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow { + bottom: 0; +} + +.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before { + top: 0; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] { + padding: 0 0.4rem; +} + +.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before { + right: 0; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] { + padding: 0.4rem 0; +} + +.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow { + top: 0; +} + +.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before { + bottom: 0; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] { + padding: 0 0.4rem; +} + +.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before { + left: 0; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.tooltip-inner { + max-width: 200px; + padding: 0.25rem 0.5rem; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 0.25rem; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: block; + max-width: 276px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; +} + +.popover .arrow { + position: absolute; + display: block; + width: 1rem; + height: 0.5rem; + margin: 0 0.3rem; +} + +.popover .arrow::before, .popover .arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-popover-top, .bs-popover-auto[x-placement^="top"] { + margin-bottom: 0.5rem; +} + +.bs-popover-top > .arrow, .bs-popover-auto[x-placement^="top"] > .arrow { + bottom: calc((0.5rem + 1px) * -1); +} + +.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^="top"] > .arrow::before { + bottom: 0; + border-width: 0.5rem 0.5rem 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^="top"] > .arrow::after { + bottom: 1px; + border-width: 0.5rem 0.5rem 0; + border-top-color: #fff; +} + +.bs-popover-right, .bs-popover-auto[x-placement^="right"] { + margin-left: 0.5rem; +} + +.bs-popover-right > .arrow, .bs-popover-auto[x-placement^="right"] > .arrow { + left: calc((0.5rem + 1px) * -1); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^="right"] > .arrow::before { + left: 0; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^="right"] > .arrow::after { + left: 1px; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: #fff; +} + +.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] { + margin-top: 0.5rem; +} + +.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^="bottom"] > .arrow { + top: calc((0.5rem + 1px) * -1); +} + +.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^="bottom"] > .arrow::before { + top: 0; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^="bottom"] > .arrow::after { + top: 1px; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: #fff; +} + +.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f7f7f7; +} + +.bs-popover-left, .bs-popover-auto[x-placement^="left"] { + margin-right: 0.5rem; +} + +.bs-popover-left > .arrow, .bs-popover-auto[x-placement^="left"] > .arrow { + right: calc((0.5rem + 1px) * -1); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^="left"] > .arrow::before { + right: 0; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^="left"] > .arrow::after { + right: 1px; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: #fff; +} + +.popover-header { + padding: 0.5rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.popover-header:empty { + display: none; +} + +.popover-body { + padding: 0.5rem 0.75rem; + color: #212529; +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transition: -webkit-transform 0.6s ease-in-out; + transition: -webkit-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-item { + -webkit-transition: none; + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-left), +.active.carousel-item-right { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-right), +.active.carousel-item-left { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + -webkit-transition-property: opacity; + transition-property: opacity; + -webkit-transform: none; + transform: none; +} + +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-left, +.carousel-fade .carousel-item-prev.carousel-item-right { + z-index: 1; + opacity: 1; +} + +.carousel-fade .active.carousel-item-left, +.carousel-fade .active.carousel-item-right { + z-index: 0; + opacity: 0; + -webkit-transition: 0s 0.6s opacity; + transition: 0s 0.6s opacity; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-left, + .carousel-fade .active.carousel-item-right { + -webkit-transition: none; + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + width: 15%; + color: #fff; + text-align: center; + opacity: 0.5; + -webkit-transition: opacity 0.15s ease; + transition: opacity 0.15s ease; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + -webkit-transition: none; + transition: none; + } +} + +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 20px; + height: 20px; + background: no-repeat 50% / 100% 100%; +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + padding-left: 0; + margin-right: 15%; + margin-left: 15%; + list-style: none; +} + +.carousel-indicators li { + -webkit-box-sizing: content-box; + box-sizing: content-box; + -webkit-box-flex: 0; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + width: 30px; + height: 3px; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: .5; + -webkit-transition: opacity 0.6s ease; + transition: opacity 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-indicators li { + -webkit-transition: none; + transition: none; + } +} + +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; +} + +@-webkit-keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.spinner-border { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + border: 0.25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + -webkit-animation: spinner-border .75s linear infinite; + animation: spinner-border .75s linear infinite; +} + +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: 0.2em; +} + +@-webkit-keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +@keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +.spinner-grow { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + -webkit-animation: spinner-grow .75s linear infinite; + animation: spinner-grow .75s linear infinite; +} + +.spinner-grow-sm { + width: 1rem; + height: 1rem; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.bg-primary { + background-color: #007bff !important; +} + +a.bg-primary:hover, a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #0062cc !important; +} + +.bg-secondary { + background-color: #6c757d !important; +} + +a.bg-secondary:hover, a.bg-secondary:focus, +button.bg-secondary:hover, +button.bg-secondary:focus { + background-color: #545b62 !important; +} + +.bg-success { + background-color: #28a745 !important; +} + +a.bg-success:hover, a.bg-success:focus, +button.bg-success:hover, +button.bg-success:focus { + background-color: #1e7e34 !important; +} + +.bg-info { + background-color: #17a2b8 !important; +} + +a.bg-info:hover, a.bg-info:focus, +button.bg-info:hover, +button.bg-info:focus { + background-color: #117a8b !important; +} + +.bg-warning { + background-color: #ffc107 !important; +} + +a.bg-warning:hover, a.bg-warning:focus, +button.bg-warning:hover, +button.bg-warning:focus { + background-color: #d39e00 !important; +} + +.bg-danger { + background-color: #dc3545 !important; +} + +a.bg-danger:hover, a.bg-danger:focus, +button.bg-danger:hover, +button.bg-danger:focus { + background-color: #bd2130 !important; +} + +.bg-light { + background-color: #f8f9fa !important; +} + +a.bg-light:hover, a.bg-light:focus, +button.bg-light:hover, +button.bg-light:focus { + background-color: #dae0e5 !important; +} + +.bg-dark { + background-color: #343a40 !important; +} + +a.bg-dark:hover, a.bg-dark:focus, +button.bg-dark:hover, +button.bg-dark:focus { + background-color: #1d2124 !important; +} + +.bg-white { + background-color: #fff !important; +} + +.bg-transparent { + background-color: transparent !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-right { + border-right: 1px solid #dee2e6 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-left { + border-left: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-right-0 { + border-right: 0 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-left-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #007bff !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #343a40 !important; +} + +.border-white { + border-color: #fff !important; +} + +.rounded-sm { + border-radius: 0.2rem !important; +} + +.rounded { + border-radius: 0.25rem !important; +} + +.rounded-top { + border-top-left-radius: 0.25rem !important; + border-top-right-radius: 0.25rem !important; +} + +.rounded-right { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-left { + border-top-left-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-lg { + border-radius: 0.3rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.d-none { + display: none !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; +} + +.d-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; +} + +@media (min-width: 576px) { + .d-sm-none { + display: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + } + .d-sm-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 768px) { + .d-md-none { + display: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + } + .d-md-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 992px) { + .d-lg-none { + display: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + } + .d-lg-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 1200px) { + .d-xl-none { + display: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + } + .d-xl-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media print { + .d-print-none { + display: none !important; + } + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: -webkit-box !important; + display: -ms-flexbox !important; + display: flex !important; + } + .d-print-inline-flex { + display: -webkit-inline-box !important; + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +.embed-responsive { + position: relative; + display: block; + width: 100%; + padding: 0; + overflow: hidden; +} + +.embed-responsive::before { + display: block; + content: ""; +} + +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +.embed-responsive-21by9::before { + padding-top: 42.85714%; +} + +.embed-responsive-16by9::before { + padding-top: 56.25%; +} + +.embed-responsive-4by3::before { + padding-top: 75%; +} + +.embed-responsive-1by1::before { + padding-top: 100%; +} + +.flex-row { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: row !important; + flex-direction: row !important; +} + +.flex-column { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; +} + +.flex-row-reverse { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + -webkit-box-orient: vertical !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; +} + +.flex-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; +} + +.flex-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; +} + +.flex-fill { + -webkit-box-flex: 1 !important; + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; +} + +.flex-grow-0 { + -webkit-box-flex: 0 !important; + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; +} + +.flex-grow-1 { + -webkit-box-flex: 1 !important; + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; +} + +.flex-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; +} + +.justify-content-start { + -webkit-box-pack: start !important; + -ms-flex-pack: start !important; + justify-content: flex-start !important; +} + +.justify-content-end { + -webkit-box-pack: end !important; + -ms-flex-pack: end !important; + justify-content: flex-end !important; +} + +.justify-content-center { + -webkit-box-pack: center !important; + -ms-flex-pack: center !important; + justify-content: center !important; +} + +.justify-content-between { + -webkit-box-pack: justify !important; + -ms-flex-pack: justify !important; + justify-content: space-between !important; +} + +.justify-content-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; +} + +.align-items-start { + -webkit-box-align: start !important; + -ms-flex-align: start !important; + align-items: flex-start !important; +} + +.align-items-end { + -webkit-box-align: end !important; + -ms-flex-align: end !important; + align-items: flex-end !important; +} + +.align-items-center { + -webkit-box-align: center !important; + -ms-flex-align: center !important; + align-items: center !important; +} + +.align-items-baseline { + -webkit-box-align: baseline !important; + -ms-flex-align: baseline !important; + align-items: baseline !important; +} + +.align-items-stretch { + -webkit-box-align: stretch !important; + -ms-flex-align: stretch !important; + align-items: stretch !important; +} + +.align-content-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; +} + +.align-content-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; +} + +.align-content-center { + -ms-flex-line-pack: center !important; + align-content: center !important; +} + +.align-content-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; +} + +.align-content-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; +} + +.align-content-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; +} + +.align-self-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; +} + +.align-self-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; +} + +.align-self-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; +} + +.align-self-center { + -ms-flex-item-align: center !important; + align-self: center !important; +} + +.align-self-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; +} + +.align-self-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; +} + +@media (min-width: 576px) { + .flex-sm-row { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-sm-column { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-sm-row-reverse { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + -webkit-box-orient: vertical !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-sm-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-sm-fill { + -webkit-box-flex: 1 !important; + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-sm-grow-0 { + -webkit-box-flex: 0 !important; + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + -webkit-box-flex: 1 !important; + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-sm-start { + -webkit-box-pack: start !important; + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-sm-end { + -webkit-box-pack: end !important; + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-sm-center { + -webkit-box-pack: center !important; + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-sm-between { + -webkit-box-pack: justify !important; + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-sm-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-sm-start { + -webkit-box-align: start !important; + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-sm-end { + -webkit-box-align: end !important; + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-sm-center { + -webkit-box-align: center !important; + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-sm-baseline { + -webkit-box-align: baseline !important; + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-sm-stretch { + -webkit-box-align: stretch !important; + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-sm-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-sm-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-sm-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-sm-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-sm-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-sm-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-sm-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-sm-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-sm-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-sm-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-sm-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-sm-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 768px) { + .flex-md-row { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-md-column { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-md-row-reverse { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + -webkit-box-orient: vertical !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-md-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-md-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-md-fill { + -webkit-box-flex: 1 !important; + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-md-grow-0 { + -webkit-box-flex: 0 !important; + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-md-grow-1 { + -webkit-box-flex: 1 !important; + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-md-start { + -webkit-box-pack: start !important; + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-md-end { + -webkit-box-pack: end !important; + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-md-center { + -webkit-box-pack: center !important; + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-md-between { + -webkit-box-pack: justify !important; + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-md-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-md-start { + -webkit-box-align: start !important; + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-md-end { + -webkit-box-align: end !important; + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-md-center { + -webkit-box-align: center !important; + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-md-baseline { + -webkit-box-align: baseline !important; + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-md-stretch { + -webkit-box-align: stretch !important; + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-md-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-md-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-md-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-md-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-md-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-md-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-md-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-md-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-md-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-md-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-md-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-md-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 992px) { + .flex-lg-row { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-lg-column { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-lg-row-reverse { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + -webkit-box-orient: vertical !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-lg-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-lg-fill { + -webkit-box-flex: 1 !important; + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-lg-grow-0 { + -webkit-box-flex: 0 !important; + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + -webkit-box-flex: 1 !important; + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-lg-start { + -webkit-box-pack: start !important; + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-lg-end { + -webkit-box-pack: end !important; + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-lg-center { + -webkit-box-pack: center !important; + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-lg-between { + -webkit-box-pack: justify !important; + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-lg-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-lg-start { + -webkit-box-align: start !important; + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-lg-end { + -webkit-box-align: end !important; + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-lg-center { + -webkit-box-align: center !important; + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-lg-baseline { + -webkit-box-align: baseline !important; + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-lg-stretch { + -webkit-box-align: stretch !important; + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-lg-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-lg-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-lg-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-lg-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-lg-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-lg-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-lg-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-lg-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-lg-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-lg-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-lg-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-lg-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 1200px) { + .flex-xl-row { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-xl-column { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-xl-row-reverse { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + -webkit-box-orient: vertical !important; + -webkit-box-direction: reverse !important; + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-xl-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-xl-fill { + -webkit-box-flex: 1 !important; + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-xl-grow-0 { + -webkit-box-flex: 0 !important; + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + -webkit-box-flex: 1 !important; + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-xl-start { + -webkit-box-pack: start !important; + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-xl-end { + -webkit-box-pack: end !important; + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-xl-center { + -webkit-box-pack: center !important; + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-xl-between { + -webkit-box-pack: justify !important; + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-xl-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-xl-start { + -webkit-box-align: start !important; + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-xl-end { + -webkit-box-align: end !important; + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-xl-center { + -webkit-box-align: center !important; + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-xl-baseline { + -webkit-box-align: baseline !important; + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-xl-stretch { + -webkit-box-align: stretch !important; + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-xl-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-xl-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-xl-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-xl-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-xl-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-xl-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-xl-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-xl-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-xl-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-xl-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-xl-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-xl-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.float-none { + float: none !important; +} + +@media (min-width: 576px) { + .float-sm-left { + float: left !important; + } + .float-sm-right { + float: right !important; + } + .float-sm-none { + float: none !important; + } +} + +@media (min-width: 768px) { + .float-md-left { + float: left !important; + } + .float-md-right { + float: right !important; + } + .float-md-none { + float: none !important; + } +} + +@media (min-width: 992px) { + .float-lg-left { + float: left !important; + } + .float-lg-right { + float: right !important; + } + .float-lg-none { + float: none !important; + } +} + +@media (min-width: 1200px) { + .float-xl-left { + float: left !important; + } + .float-xl-right { + float: right !important; + } + .float-xl-none { + float: none !important; + } +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +@supports ((position: -webkit-sticky) or (position: sticky)) { + .sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.sr-only-focusable:active, .sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; +} + +.shadow-sm { + -webkit-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow { + -webkit-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-lg { + -webkit-box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.vw-100 { + width: 100vw !important; +} + +.vh-100 { + height: 100vh !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + pointer-events: auto; + content: ""; + background-color: rgba(0, 0, 0, 0); +} + +.m-0 { + margin: 0 !important; +} + +.mt-0, +.my-0 { + margin-top: 0 !important; +} + +.mr-0, +.mx-0 { + margin-right: 0 !important; +} + +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} + +.ml-0, +.mx-0 { + margin-left: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} + +.mr-1, +.mx-1 { + margin-right: 0.25rem !important; +} + +.mb-1, +.my-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} + +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} + +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.mt-3, +.my-3 { + margin-top: 1rem !important; +} + +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem !important; +} + +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} + +.mr-4, +.mx-4 { + margin-right: 1.5rem !important; +} + +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} + +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.mt-5, +.my-5 { + margin-top: 3rem !important; +} + +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} + +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} + +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0, +.py-0 { + padding-top: 0 !important; +} + +.pr-0, +.px-0 { + padding-right: 0 !important; +} + +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} + +.pl-0, +.px-0 { + padding-left: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} + +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} + +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} + +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} + +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.pt-3, +.py-3 { + padding-top: 1rem !important; +} + +.pr-3, +.px-3 { + padding-right: 1rem !important; +} + +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} + +.pl-3, +.px-3 { + padding-left: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} + +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} + +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} + +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.pt-5, +.py-5 { + padding-top: 3rem !important; +} + +.pr-5, +.px-5 { + padding-right: 3rem !important; +} + +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} + +.pl-5, +.px-5 { + padding-left: 3rem !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} + +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} + +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} + +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} + +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} + +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} + +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} + +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} + +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} + +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} + +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} + +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} + +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} + +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} + +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} + +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto, +.my-auto { + margin-top: auto !important; +} + +.mr-auto, +.mx-auto { + margin-right: auto !important; +} + +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; +} + +@media (min-width: 576px) { + .m-sm-0 { + margin: 0 !important; + } + .mt-sm-0, + .my-sm-0 { + margin-top: 0 !important; + } + .mr-sm-0, + .mx-sm-0 { + margin-right: 0 !important; + } + .mb-sm-0, + .my-sm-0 { + margin-bottom: 0 !important; + } + .ml-sm-0, + .mx-sm-0 { + margin-left: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .mt-sm-1, + .my-sm-1 { + margin-top: 0.25rem !important; + } + .mr-sm-1, + .mx-sm-1 { + margin-right: 0.25rem !important; + } + .mb-sm-1, + .my-sm-1 { + margin-bottom: 0.25rem !important; + } + .ml-sm-1, + .mx-sm-1 { + margin-left: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .mt-sm-2, + .my-sm-2 { + margin-top: 0.5rem !important; + } + .mr-sm-2, + .mx-sm-2 { + margin-right: 0.5rem !important; + } + .mb-sm-2, + .my-sm-2 { + margin-bottom: 0.5rem !important; + } + .ml-sm-2, + .mx-sm-2 { + margin-left: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .mt-sm-3, + .my-sm-3 { + margin-top: 1rem !important; + } + .mr-sm-3, + .mx-sm-3 { + margin-right: 1rem !important; + } + .mb-sm-3, + .my-sm-3 { + margin-bottom: 1rem !important; + } + .ml-sm-3, + .mx-sm-3 { + margin-left: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .mt-sm-4, + .my-sm-4 { + margin-top: 1.5rem !important; + } + .mr-sm-4, + .mx-sm-4 { + margin-right: 1.5rem !important; + } + .mb-sm-4, + .my-sm-4 { + margin-bottom: 1.5rem !important; + } + .ml-sm-4, + .mx-sm-4 { + margin-left: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .mt-sm-5, + .my-sm-5 { + margin-top: 3rem !important; + } + .mr-sm-5, + .mx-sm-5 { + margin-right: 3rem !important; + } + .mb-sm-5, + .my-sm-5 { + margin-bottom: 3rem !important; + } + .ml-sm-5, + .mx-sm-5 { + margin-left: 3rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .pt-sm-0, + .py-sm-0 { + padding-top: 0 !important; + } + .pr-sm-0, + .px-sm-0 { + padding-right: 0 !important; + } + .pb-sm-0, + .py-sm-0 { + padding-bottom: 0 !important; + } + .pl-sm-0, + .px-sm-0 { + padding-left: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .pt-sm-1, + .py-sm-1 { + padding-top: 0.25rem !important; + } + .pr-sm-1, + .px-sm-1 { + padding-right: 0.25rem !important; + } + .pb-sm-1, + .py-sm-1 { + padding-bottom: 0.25rem !important; + } + .pl-sm-1, + .px-sm-1 { + padding-left: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .pt-sm-2, + .py-sm-2 { + padding-top: 0.5rem !important; + } + .pr-sm-2, + .px-sm-2 { + padding-right: 0.5rem !important; + } + .pb-sm-2, + .py-sm-2 { + padding-bottom: 0.5rem !important; + } + .pl-sm-2, + .px-sm-2 { + padding-left: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .pt-sm-3, + .py-sm-3 { + padding-top: 1rem !important; + } + .pr-sm-3, + .px-sm-3 { + padding-right: 1rem !important; + } + .pb-sm-3, + .py-sm-3 { + padding-bottom: 1rem !important; + } + .pl-sm-3, + .px-sm-3 { + padding-left: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .pt-sm-4, + .py-sm-4 { + padding-top: 1.5rem !important; + } + .pr-sm-4, + .px-sm-4 { + padding-right: 1.5rem !important; + } + .pb-sm-4, + .py-sm-4 { + padding-bottom: 1.5rem !important; + } + .pl-sm-4, + .px-sm-4 { + padding-left: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .pt-sm-5, + .py-sm-5 { + padding-top: 3rem !important; + } + .pr-sm-5, + .px-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-5, + .py-sm-5 { + padding-bottom: 3rem !important; + } + .pl-sm-5, + .px-sm-5 { + padding-left: 3rem !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .mt-sm-n1, + .my-sm-n1 { + margin-top: -0.25rem !important; + } + .mr-sm-n1, + .mx-sm-n1 { + margin-right: -0.25rem !important; + } + .mb-sm-n1, + .my-sm-n1 { + margin-bottom: -0.25rem !important; + } + .ml-sm-n1, + .mx-sm-n1 { + margin-left: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .mt-sm-n2, + .my-sm-n2 { + margin-top: -0.5rem !important; + } + .mr-sm-n2, + .mx-sm-n2 { + margin-right: -0.5rem !important; + } + .mb-sm-n2, + .my-sm-n2 { + margin-bottom: -0.5rem !important; + } + .ml-sm-n2, + .mx-sm-n2 { + margin-left: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .mt-sm-n3, + .my-sm-n3 { + margin-top: -1rem !important; + } + .mr-sm-n3, + .mx-sm-n3 { + margin-right: -1rem !important; + } + .mb-sm-n3, + .my-sm-n3 { + margin-bottom: -1rem !important; + } + .ml-sm-n3, + .mx-sm-n3 { + margin-left: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .mt-sm-n4, + .my-sm-n4 { + margin-top: -1.5rem !important; + } + .mr-sm-n4, + .mx-sm-n4 { + margin-right: -1.5rem !important; + } + .mb-sm-n4, + .my-sm-n4 { + margin-bottom: -1.5rem !important; + } + .ml-sm-n4, + .mx-sm-n4 { + margin-left: -1.5rem !important; + } + .m-sm-n5 { + margin: -3rem !important; + } + .mt-sm-n5, + .my-sm-n5 { + margin-top: -3rem !important; + } + .mr-sm-n5, + .mx-sm-n5 { + margin-right: -3rem !important; + } + .mb-sm-n5, + .my-sm-n5 { + margin-bottom: -3rem !important; + } + .ml-sm-n5, + .mx-sm-n5 { + margin-left: -3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mt-sm-auto, + .my-sm-auto { + margin-top: auto !important; + } + .mr-sm-auto, + .mx-sm-auto { + margin-right: auto !important; + } + .mb-sm-auto, + .my-sm-auto { + margin-bottom: auto !important; + } + .ml-sm-auto, + .mx-sm-auto { + margin-left: auto !important; + } +} + +@media (min-width: 768px) { + .m-md-0 { + margin: 0 !important; + } + .mt-md-0, + .my-md-0 { + margin-top: 0 !important; + } + .mr-md-0, + .mx-md-0 { + margin-right: 0 !important; + } + .mb-md-0, + .my-md-0 { + margin-bottom: 0 !important; + } + .ml-md-0, + .mx-md-0 { + margin-left: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .mt-md-1, + .my-md-1 { + margin-top: 0.25rem !important; + } + .mr-md-1, + .mx-md-1 { + margin-right: 0.25rem !important; + } + .mb-md-1, + .my-md-1 { + margin-bottom: 0.25rem !important; + } + .ml-md-1, + .mx-md-1 { + margin-left: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .mt-md-2, + .my-md-2 { + margin-top: 0.5rem !important; + } + .mr-md-2, + .mx-md-2 { + margin-right: 0.5rem !important; + } + .mb-md-2, + .my-md-2 { + margin-bottom: 0.5rem !important; + } + .ml-md-2, + .mx-md-2 { + margin-left: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .mt-md-3, + .my-md-3 { + margin-top: 1rem !important; + } + .mr-md-3, + .mx-md-3 { + margin-right: 1rem !important; + } + .mb-md-3, + .my-md-3 { + margin-bottom: 1rem !important; + } + .ml-md-3, + .mx-md-3 { + margin-left: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .mt-md-4, + .my-md-4 { + margin-top: 1.5rem !important; + } + .mr-md-4, + .mx-md-4 { + margin-right: 1.5rem !important; + } + .mb-md-4, + .my-md-4 { + margin-bottom: 1.5rem !important; + } + .ml-md-4, + .mx-md-4 { + margin-left: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .mt-md-5, + .my-md-5 { + margin-top: 3rem !important; + } + .mr-md-5, + .mx-md-5 { + margin-right: 3rem !important; + } + .mb-md-5, + .my-md-5 { + margin-bottom: 3rem !important; + } + .ml-md-5, + .mx-md-5 { + margin-left: 3rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .pt-md-0, + .py-md-0 { + padding-top: 0 !important; + } + .pr-md-0, + .px-md-0 { + padding-right: 0 !important; + } + .pb-md-0, + .py-md-0 { + padding-bottom: 0 !important; + } + .pl-md-0, + .px-md-0 { + padding-left: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .pt-md-1, + .py-md-1 { + padding-top: 0.25rem !important; + } + .pr-md-1, + .px-md-1 { + padding-right: 0.25rem !important; + } + .pb-md-1, + .py-md-1 { + padding-bottom: 0.25rem !important; + } + .pl-md-1, + .px-md-1 { + padding-left: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .pt-md-2, + .py-md-2 { + padding-top: 0.5rem !important; + } + .pr-md-2, + .px-md-2 { + padding-right: 0.5rem !important; + } + .pb-md-2, + .py-md-2 { + padding-bottom: 0.5rem !important; + } + .pl-md-2, + .px-md-2 { + padding-left: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .pt-md-3, + .py-md-3 { + padding-top: 1rem !important; + } + .pr-md-3, + .px-md-3 { + padding-right: 1rem !important; + } + .pb-md-3, + .py-md-3 { + padding-bottom: 1rem !important; + } + .pl-md-3, + .px-md-3 { + padding-left: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .pt-md-4, + .py-md-4 { + padding-top: 1.5rem !important; + } + .pr-md-4, + .px-md-4 { + padding-right: 1.5rem !important; + } + .pb-md-4, + .py-md-4 { + padding-bottom: 1.5rem !important; + } + .pl-md-4, + .px-md-4 { + padding-left: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .pt-md-5, + .py-md-5 { + padding-top: 3rem !important; + } + .pr-md-5, + .px-md-5 { + padding-right: 3rem !important; + } + .pb-md-5, + .py-md-5 { + padding-bottom: 3rem !important; + } + .pl-md-5, + .px-md-5 { + padding-left: 3rem !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .mt-md-n1, + .my-md-n1 { + margin-top: -0.25rem !important; + } + .mr-md-n1, + .mx-md-n1 { + margin-right: -0.25rem !important; + } + .mb-md-n1, + .my-md-n1 { + margin-bottom: -0.25rem !important; + } + .ml-md-n1, + .mx-md-n1 { + margin-left: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .mt-md-n2, + .my-md-n2 { + margin-top: -0.5rem !important; + } + .mr-md-n2, + .mx-md-n2 { + margin-right: -0.5rem !important; + } + .mb-md-n2, + .my-md-n2 { + margin-bottom: -0.5rem !important; + } + .ml-md-n2, + .mx-md-n2 { + margin-left: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .mt-md-n3, + .my-md-n3 { + margin-top: -1rem !important; + } + .mr-md-n3, + .mx-md-n3 { + margin-right: -1rem !important; + } + .mb-md-n3, + .my-md-n3 { + margin-bottom: -1rem !important; + } + .ml-md-n3, + .mx-md-n3 { + margin-left: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .mt-md-n4, + .my-md-n4 { + margin-top: -1.5rem !important; + } + .mr-md-n4, + .mx-md-n4 { + margin-right: -1.5rem !important; + } + .mb-md-n4, + .my-md-n4 { + margin-bottom: -1.5rem !important; + } + .ml-md-n4, + .mx-md-n4 { + margin-left: -1.5rem !important; + } + .m-md-n5 { + margin: -3rem !important; + } + .mt-md-n5, + .my-md-n5 { + margin-top: -3rem !important; + } + .mr-md-n5, + .mx-md-n5 { + margin-right: -3rem !important; + } + .mb-md-n5, + .my-md-n5 { + margin-bottom: -3rem !important; + } + .ml-md-n5, + .mx-md-n5 { + margin-left: -3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mt-md-auto, + .my-md-auto { + margin-top: auto !important; + } + .mr-md-auto, + .mx-md-auto { + margin-right: auto !important; + } + .mb-md-auto, + .my-md-auto { + margin-bottom: auto !important; + } + .ml-md-auto, + .mx-md-auto { + margin-left: auto !important; + } +} + +@media (min-width: 992px) { + .m-lg-0 { + margin: 0 !important; + } + .mt-lg-0, + .my-lg-0 { + margin-top: 0 !important; + } + .mr-lg-0, + .mx-lg-0 { + margin-right: 0 !important; + } + .mb-lg-0, + .my-lg-0 { + margin-bottom: 0 !important; + } + .ml-lg-0, + .mx-lg-0 { + margin-left: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .mt-lg-1, + .my-lg-1 { + margin-top: 0.25rem !important; + } + .mr-lg-1, + .mx-lg-1 { + margin-right: 0.25rem !important; + } + .mb-lg-1, + .my-lg-1 { + margin-bottom: 0.25rem !important; + } + .ml-lg-1, + .mx-lg-1 { + margin-left: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .mt-lg-2, + .my-lg-2 { + margin-top: 0.5rem !important; + } + .mr-lg-2, + .mx-lg-2 { + margin-right: 0.5rem !important; + } + .mb-lg-2, + .my-lg-2 { + margin-bottom: 0.5rem !important; + } + .ml-lg-2, + .mx-lg-2 { + margin-left: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .mt-lg-3, + .my-lg-3 { + margin-top: 1rem !important; + } + .mr-lg-3, + .mx-lg-3 { + margin-right: 1rem !important; + } + .mb-lg-3, + .my-lg-3 { + margin-bottom: 1rem !important; + } + .ml-lg-3, + .mx-lg-3 { + margin-left: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .mt-lg-4, + .my-lg-4 { + margin-top: 1.5rem !important; + } + .mr-lg-4, + .mx-lg-4 { + margin-right: 1.5rem !important; + } + .mb-lg-4, + .my-lg-4 { + margin-bottom: 1.5rem !important; + } + .ml-lg-4, + .mx-lg-4 { + margin-left: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .mt-lg-5, + .my-lg-5 { + margin-top: 3rem !important; + } + .mr-lg-5, + .mx-lg-5 { + margin-right: 3rem !important; + } + .mb-lg-5, + .my-lg-5 { + margin-bottom: 3rem !important; + } + .ml-lg-5, + .mx-lg-5 { + margin-left: 3rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .pt-lg-0, + .py-lg-0 { + padding-top: 0 !important; + } + .pr-lg-0, + .px-lg-0 { + padding-right: 0 !important; + } + .pb-lg-0, + .py-lg-0 { + padding-bottom: 0 !important; + } + .pl-lg-0, + .px-lg-0 { + padding-left: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .pt-lg-1, + .py-lg-1 { + padding-top: 0.25rem !important; + } + .pr-lg-1, + .px-lg-1 { + padding-right: 0.25rem !important; + } + .pb-lg-1, + .py-lg-1 { + padding-bottom: 0.25rem !important; + } + .pl-lg-1, + .px-lg-1 { + padding-left: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .pt-lg-2, + .py-lg-2 { + padding-top: 0.5rem !important; + } + .pr-lg-2, + .px-lg-2 { + padding-right: 0.5rem !important; + } + .pb-lg-2, + .py-lg-2 { + padding-bottom: 0.5rem !important; + } + .pl-lg-2, + .px-lg-2 { + padding-left: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .pt-lg-3, + .py-lg-3 { + padding-top: 1rem !important; + } + .pr-lg-3, + .px-lg-3 { + padding-right: 1rem !important; + } + .pb-lg-3, + .py-lg-3 { + padding-bottom: 1rem !important; + } + .pl-lg-3, + .px-lg-3 { + padding-left: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .pt-lg-4, + .py-lg-4 { + padding-top: 1.5rem !important; + } + .pr-lg-4, + .px-lg-4 { + padding-right: 1.5rem !important; + } + .pb-lg-4, + .py-lg-4 { + padding-bottom: 1.5rem !important; + } + .pl-lg-4, + .px-lg-4 { + padding-left: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .pt-lg-5, + .py-lg-5 { + padding-top: 3rem !important; + } + .pr-lg-5, + .px-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-5, + .py-lg-5 { + padding-bottom: 3rem !important; + } + .pl-lg-5, + .px-lg-5 { + padding-left: 3rem !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .mt-lg-n1, + .my-lg-n1 { + margin-top: -0.25rem !important; + } + .mr-lg-n1, + .mx-lg-n1 { + margin-right: -0.25rem !important; + } + .mb-lg-n1, + .my-lg-n1 { + margin-bottom: -0.25rem !important; + } + .ml-lg-n1, + .mx-lg-n1 { + margin-left: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .mt-lg-n2, + .my-lg-n2 { + margin-top: -0.5rem !important; + } + .mr-lg-n2, + .mx-lg-n2 { + margin-right: -0.5rem !important; + } + .mb-lg-n2, + .my-lg-n2 { + margin-bottom: -0.5rem !important; + } + .ml-lg-n2, + .mx-lg-n2 { + margin-left: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .mt-lg-n3, + .my-lg-n3 { + margin-top: -1rem !important; + } + .mr-lg-n3, + .mx-lg-n3 { + margin-right: -1rem !important; + } + .mb-lg-n3, + .my-lg-n3 { + margin-bottom: -1rem !important; + } + .ml-lg-n3, + .mx-lg-n3 { + margin-left: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .mt-lg-n4, + .my-lg-n4 { + margin-top: -1.5rem !important; + } + .mr-lg-n4, + .mx-lg-n4 { + margin-right: -1.5rem !important; + } + .mb-lg-n4, + .my-lg-n4 { + margin-bottom: -1.5rem !important; + } + .ml-lg-n4, + .mx-lg-n4 { + margin-left: -1.5rem !important; + } + .m-lg-n5 { + margin: -3rem !important; + } + .mt-lg-n5, + .my-lg-n5 { + margin-top: -3rem !important; + } + .mr-lg-n5, + .mx-lg-n5 { + margin-right: -3rem !important; + } + .mb-lg-n5, + .my-lg-n5 { + margin-bottom: -3rem !important; + } + .ml-lg-n5, + .mx-lg-n5 { + margin-left: -3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mt-lg-auto, + .my-lg-auto { + margin-top: auto !important; + } + .mr-lg-auto, + .mx-lg-auto { + margin-right: auto !important; + } + .mb-lg-auto, + .my-lg-auto { + margin-bottom: auto !important; + } + .ml-lg-auto, + .mx-lg-auto { + margin-left: auto !important; + } +} + +@media (min-width: 1200px) { + .m-xl-0 { + margin: 0 !important; + } + .mt-xl-0, + .my-xl-0 { + margin-top: 0 !important; + } + .mr-xl-0, + .mx-xl-0 { + margin-right: 0 !important; + } + .mb-xl-0, + .my-xl-0 { + margin-bottom: 0 !important; + } + .ml-xl-0, + .mx-xl-0 { + margin-left: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .mt-xl-1, + .my-xl-1 { + margin-top: 0.25rem !important; + } + .mr-xl-1, + .mx-xl-1 { + margin-right: 0.25rem !important; + } + .mb-xl-1, + .my-xl-1 { + margin-bottom: 0.25rem !important; + } + .ml-xl-1, + .mx-xl-1 { + margin-left: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .mt-xl-2, + .my-xl-2 { + margin-top: 0.5rem !important; + } + .mr-xl-2, + .mx-xl-2 { + margin-right: 0.5rem !important; + } + .mb-xl-2, + .my-xl-2 { + margin-bottom: 0.5rem !important; + } + .ml-xl-2, + .mx-xl-2 { + margin-left: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .mt-xl-3, + .my-xl-3 { + margin-top: 1rem !important; + } + .mr-xl-3, + .mx-xl-3 { + margin-right: 1rem !important; + } + .mb-xl-3, + .my-xl-3 { + margin-bottom: 1rem !important; + } + .ml-xl-3, + .mx-xl-3 { + margin-left: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .mt-xl-4, + .my-xl-4 { + margin-top: 1.5rem !important; + } + .mr-xl-4, + .mx-xl-4 { + margin-right: 1.5rem !important; + } + .mb-xl-4, + .my-xl-4 { + margin-bottom: 1.5rem !important; + } + .ml-xl-4, + .mx-xl-4 { + margin-left: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .mt-xl-5, + .my-xl-5 { + margin-top: 3rem !important; + } + .mr-xl-5, + .mx-xl-5 { + margin-right: 3rem !important; + } + .mb-xl-5, + .my-xl-5 { + margin-bottom: 3rem !important; + } + .ml-xl-5, + .mx-xl-5 { + margin-left: 3rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .pt-xl-0, + .py-xl-0 { + padding-top: 0 !important; + } + .pr-xl-0, + .px-xl-0 { + padding-right: 0 !important; + } + .pb-xl-0, + .py-xl-0 { + padding-bottom: 0 !important; + } + .pl-xl-0, + .px-xl-0 { + padding-left: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .pt-xl-1, + .py-xl-1 { + padding-top: 0.25rem !important; + } + .pr-xl-1, + .px-xl-1 { + padding-right: 0.25rem !important; + } + .pb-xl-1, + .py-xl-1 { + padding-bottom: 0.25rem !important; + } + .pl-xl-1, + .px-xl-1 { + padding-left: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .pt-xl-2, + .py-xl-2 { + padding-top: 0.5rem !important; + } + .pr-xl-2, + .px-xl-2 { + padding-right: 0.5rem !important; + } + .pb-xl-2, + .py-xl-2 { + padding-bottom: 0.5rem !important; + } + .pl-xl-2, + .px-xl-2 { + padding-left: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .pt-xl-3, + .py-xl-3 { + padding-top: 1rem !important; + } + .pr-xl-3, + .px-xl-3 { + padding-right: 1rem !important; + } + .pb-xl-3, + .py-xl-3 { + padding-bottom: 1rem !important; + } + .pl-xl-3, + .px-xl-3 { + padding-left: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .pt-xl-4, + .py-xl-4 { + padding-top: 1.5rem !important; + } + .pr-xl-4, + .px-xl-4 { + padding-right: 1.5rem !important; + } + .pb-xl-4, + .py-xl-4 { + padding-bottom: 1.5rem !important; + } + .pl-xl-4, + .px-xl-4 { + padding-left: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .pt-xl-5, + .py-xl-5 { + padding-top: 3rem !important; + } + .pr-xl-5, + .px-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-5, + .py-xl-5 { + padding-bottom: 3rem !important; + } + .pl-xl-5, + .px-xl-5 { + padding-left: 3rem !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .mt-xl-n1, + .my-xl-n1 { + margin-top: -0.25rem !important; + } + .mr-xl-n1, + .mx-xl-n1 { + margin-right: -0.25rem !important; + } + .mb-xl-n1, + .my-xl-n1 { + margin-bottom: -0.25rem !important; + } + .ml-xl-n1, + .mx-xl-n1 { + margin-left: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .mt-xl-n2, + .my-xl-n2 { + margin-top: -0.5rem !important; + } + .mr-xl-n2, + .mx-xl-n2 { + margin-right: -0.5rem !important; + } + .mb-xl-n2, + .my-xl-n2 { + margin-bottom: -0.5rem !important; + } + .ml-xl-n2, + .mx-xl-n2 { + margin-left: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .mt-xl-n3, + .my-xl-n3 { + margin-top: -1rem !important; + } + .mr-xl-n3, + .mx-xl-n3 { + margin-right: -1rem !important; + } + .mb-xl-n3, + .my-xl-n3 { + margin-bottom: -1rem !important; + } + .ml-xl-n3, + .mx-xl-n3 { + margin-left: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .mt-xl-n4, + .my-xl-n4 { + margin-top: -1.5rem !important; + } + .mr-xl-n4, + .mx-xl-n4 { + margin-right: -1.5rem !important; + } + .mb-xl-n4, + .my-xl-n4 { + margin-bottom: -1.5rem !important; + } + .ml-xl-n4, + .mx-xl-n4 { + margin-left: -1.5rem !important; + } + .m-xl-n5 { + margin: -3rem !important; + } + .mt-xl-n5, + .my-xl-n5 { + margin-top: -3rem !important; + } + .mr-xl-n5, + .mx-xl-n5 { + margin-right: -3rem !important; + } + .mb-xl-n5, + .my-xl-n5 { + margin-bottom: -3rem !important; + } + .ml-xl-n5, + .mx-xl-n5 { + margin-left: -3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mt-xl-auto, + .my-xl-auto { + margin-top: auto !important; + } + .mr-xl-auto, + .mx-xl-auto { + margin-right: auto !important; + } + .mb-xl-auto, + .my-xl-auto { + margin-bottom: auto !important; + } + .ml-xl-auto, + .mx-xl-auto { + margin-left: auto !important; + } +} + +.text-monospace { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important; +} + +.text-justify { + text-align: justify !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +@media (min-width: 576px) { + .text-sm-left { + text-align: left !important; + } + .text-sm-right { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .text-md-left { + text-align: left !important; + } + .text-md-right { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .text-lg-left { + text-align: left !important; + } + .text-lg-right { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .text-xl-left { + text-align: left !important; + } + .text-xl-right { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.font-weight-light { + font-weight: 300 !important; +} + +.font-weight-lighter { + font-weight: lighter !important; +} + +.font-weight-normal { + font-weight: 400 !important; +} + +.font-weight-bold { + font-weight: 700 !important; +} + +.font-weight-bolder { + font-weight: bolder !important; +} + +.font-italic { + font-style: italic !important; +} + +.text-white { + color: #fff !important; +} + +.text-primary { + color: #007bff !important; +} + +a.text-primary:hover, a.text-primary:focus { + color: #0056b3 !important; +} + +.text-secondary { + color: #6c757d !important; +} + +a.text-secondary:hover, a.text-secondary:focus { + color: #494f54 !important; +} + +.text-success { + color: #28a745 !important; +} + +a.text-success:hover, a.text-success:focus { + color: #19692c !important; +} + +.text-info { + color: #17a2b8 !important; +} + +a.text-info:hover, a.text-info:focus { + color: #0f6674 !important; +} + +.text-warning { + color: #ffc107 !important; +} + +a.text-warning:hover, a.text-warning:focus { + color: #ba8b00 !important; +} + +.text-danger { + color: #dc3545 !important; +} + +a.text-danger:hover, a.text-danger:focus { + color: #a71d2a !important; +} + +.text-light { + color: #f8f9fa !important; +} + +a.text-light:hover, a.text-light:focus { + color: #cbd3da !important; +} + +.text-dark { + color: #343a40 !important; +} + +a.text-dark:hover, a.text-dark:focus { + color: #121416 !important; +} + +.text-body { + color: #212529 !important; +} + +.text-muted { + color: #6c757d !important; +} + +.text-black-50 { + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-break { + word-break: break-word !important; + overflow-wrap: break-word !important; +} + +.text-reset { + color: inherit !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media print { + *, + *::before, + *::after { + text-shadow: none !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + } + a:not(.btn) { + text-decoration: underline; + } + abbr[title]::after { + content: " (" attr(title) ")"; + } + pre { + white-space: pre-wrap !important; + } + pre, + blockquote { + border: 1px solid #adb5bd; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + @page { + size: a3; + } + body { + min-width: 992px !important; + } + .container { + min-width: 992px !important; + } + .navbar { + display: none; + } + .badge { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #dee2e6 !important; + } + .table-dark { + color: inherit; + } + .table-dark th, + .table-dark td, + .table-dark thead th, + .table-dark tbody + tbody { + border-color: #dee2e6; + } + .table .thead-dark th { + color: inherit; + border-color: #dee2e6; + } +} + +html { + position: relative; + min-height: 100%; +} + +body { + height: 100%; +} + +#wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +#wrapper #content-wrapper { + overflow-x: hidden; + width: 100%; + padding-top: 1rem; + padding-bottom: 80px; +} + +.scroll-to-top { + position: fixed; + right: 15px; + bottom: 15px; + display: none; + width: 50px; + height: 50px; + text-align: center; + color: #fff; + background: rgba(52, 58, 64, 0.5); + line-height: 46px; +} + +.scroll-to-top:focus, .scroll-to-top:hover { + color: white; +} + +.scroll-to-top:hover { + background: #343a40; +} + +.scroll-to-top i { + font-weight: 800; +} + +.smaller { + font-size: 0.7rem; +} + +.o-hidden { + overflow: hidden !important; +} + +.z-0 { + z-index: 0; +} + +.z-1 { + z-index: 1; +} + +.navbar-nav .form-inline .input-group { + width: 100%; +} + +.navbar-nav .nav-item.active .nav-link { + color: #fff; +} + +.navbar-nav .nav-item.dropdown .dropdown-toggle::after { + width: 1rem; + text-align: center; + float: right; + vertical-align: 0; + border: 0; + font-weight: 900; + content: '\f105'; + font-family: 'Font Awesome 5 Free'; +} + +.navbar-nav .nav-item.dropdown.show .dropdown-toggle::after { + content: '\f107'; +} + +.navbar-nav .nav-item.dropdown.no-arrow .dropdown-toggle::after { + display: none; +} + +.navbar-nav .nav-item .nav-link:focus { + outline: none; +} + +.navbar-nav .nav-item .nav-link .badge { + position: absolute; + margin-left: 0.75rem; + top: 0.3rem; + font-weight: 400; + font-size: 0.5rem; +} + +@media (min-width: 768px) { + .navbar-nav .form-inline .input-group { + width: auto; + } +} + +.sidebar { + width: 90px !important; + background-color: #212529; + min-height: calc(100vh - 56px); +} + +.sidebar .nav-item:last-child { + margin-bottom: 1rem; +} + +.sidebar .nav-item .nav-link { + text-align: center; + padding: 0.75rem 1rem; + width: 90px; +} + +.sidebar .nav-item .nav-link span { + font-size: 0.65rem; + display: block; +} + +.sidebar .nav-item .dropdown-menu { + position: absolute !important; + -webkit-transform: none !important; + transform: none !important; + left: calc(90px + 0.5rem) !important; + margin: 0; +} + +.sidebar .nav-item .dropdown-menu.dropup { + bottom: 0; + top: auto !important; +} + +.sidebar .nav-item.dropdown .dropdown-toggle::after { + display: none; +} + +.sidebar .nav-item .nav-link { + color: rgba(255, 255, 255, 0.5); +} + +.sidebar .nav-item .nav-link:active, .sidebar .nav-item .nav-link:focus, .sidebar .nav-item .nav-link:hover { + color: rgba(255, 255, 255, 0.75); +} + +.sidebar.toggled { + width: 0 !important; + overflow: hidden; +} + +@media (min-width: 768px) { + .sidebar { + width: 225px !important; + } + .sidebar .nav-item .nav-link { + display: block; + width: 100%; + text-align: left; + padding: 1rem; + width: 225px; + } + .sidebar .nav-item .nav-link span { + font-size: 1rem; + display: inline; + } + .sidebar .nav-item .dropdown-menu { + position: static !important; + margin: 0 1rem; + top: 0; + } + .sidebar .nav-item.dropdown .dropdown-toggle::after { + display: block; + } + .sidebar.toggled { + overflow: visible; + width: 90px !important; + } + .sidebar.toggled .nav-item:last-child { + margin-bottom: 1rem; + } + .sidebar.toggled .nav-item .nav-link { + text-align: center; + padding: 0.75rem 1rem; + width: 90px; + } + .sidebar.toggled .nav-item .nav-link span { + font-size: 0.65rem; + display: block; + } + .sidebar.toggled .nav-item .dropdown-menu { + position: absolute !important; + -webkit-transform: none !important; + transform: none !important; + left: calc(90px + 0.5rem) !important; + margin: 0; + } + .sidebar.toggled .nav-item .dropdown-menu.dropup { + bottom: 0; + top: auto !important; + } + .sidebar.toggled .nav-item.dropdown .dropdown-toggle::after { + display: none; + } +} + +.card-body-icon { + position: absolute; + z-index: 0; + top: -1.25rem; + right: -1rem; + opacity: 0.4; + font-size: 5rem; + -webkit-transform: rotate(15deg); + transform: rotate(15deg); +} + +@media (min-width: 576px) { + .card-columns { + -webkit-column-count: 1; + -moz-column-count: 1; + column-count: 1; + } +} + +@media (min-width: 768px) { + .card-columns { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + } +} + +@media (min-width: 1200px) { + .card-columns { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + } +} + +:root { + --input-padding-x: 0.75rem; + --input-padding-y: 0.75rem; +} + +.card-login { + max-width: 25rem; +} + +.card-register { + max-width: 40rem; +} + +.form-label-group { + position: relative; +} + +.form-label-group > input, +.form-label-group > label { + padding: var(--input-padding-y) var(--input-padding-x); + height: auto; +} + +.form-label-group > label { + position: absolute; + top: 0; + left: 0; + display: block; + width: 100%; + margin-bottom: 0; + /* Override default `