From 12d582a0fb6081c0616186fc235a8a85b4eb52d7 Mon Sep 17 00:00:00 2001 From: woniuzfb <47843848+woniuzfb@users.noreply.github.com> Date: Sun, 5 May 2024 16:15:08 +0800 Subject: [PATCH] feat: postgresql,docker,traefik,authelia,yq --- README.md | 2 + build | 2 +- core | 8 +- docs/iptv.sh | 15 +- env | 10 + iptv.sh | 15 +- make | 2 +- scripts/build.sh | 10 +- scripts/docker/certs/openssl.cnf | 385 ++++++++++++++++++ .../data/authelia/config/configuration.yml | 77 ++++ .../data/authelia/config/users_database.yml | 20 + .../docker/data/authelia/secrets/JWT_SECRET | 0 .../authelia/secrets/SESSION_REDIS_PASSWORD | 0 .../data/authelia/secrets/SESSION_SECRET | 0 .../authelia/secrets/STORAGE_ENCRYPTION_KEY | 0 .../secrets/STORAGE_POSTGRES_PASSWORD | 0 .../docker/data/traefik/config/dynamic.yml | 110 +++++ .../docker/data/traefik/config/traefik.yml | 58 +++ scripts/docker/docker-compose.yml | 138 +++++++ src/calibre/kcc | 2 +- src/calibre/web | 2 +- src/docker/crt | 120 ++++++ src/docker/install | 10 +- src/docker/service | 300 ++++++++++++++ src/dr | 22 + src/nginx/add_domain | 4 +- src/nginx/config_nodejs | 5 +- src/nginx/sites_crt | 103 ++++- src/nx | 1 - src/or | 1 - src/pve | 7 +- src/tv | 1 - utils/curl | 2 +- utils/git | 30 +- utils/inquirer | 15 +- utils/iperf | 2 +- utils/postgresql | 160 ++++++++ utils/shfile | 1 + utils/system | 16 +- utils/tesseract | 2 +- utils/vim | 2 +- utils/yq | 62 +++ 42 files changed, 1635 insertions(+), 87 deletions(-) create mode 100644 scripts/docker/certs/openssl.cnf create mode 100644 scripts/docker/data/authelia/config/configuration.yml create mode 100644 scripts/docker/data/authelia/config/users_database.yml create mode 100644 scripts/docker/data/authelia/secrets/JWT_SECRET create mode 100644 scripts/docker/data/authelia/secrets/SESSION_REDIS_PASSWORD create mode 100644 scripts/docker/data/authelia/secrets/SESSION_SECRET create mode 100644 scripts/docker/data/authelia/secrets/STORAGE_ENCRYPTION_KEY create mode 100644 scripts/docker/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD create mode 100644 scripts/docker/data/traefik/config/dynamic.yml create mode 100644 scripts/docker/data/traefik/config/traefik.yml create mode 100644 scripts/docker/docker-compose.yml create mode 100644 src/docker/crt create mode 100644 src/docker/service create mode 100644 utils/postgresql create mode 100644 utils/yq diff --git a/README.md b/README.md index 19caa84..e4aad16 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,8 @@ wget https://woniuzfb.github.io/iptv/iptv.sh && bash iptv.sh - traefik - authelia +- postgresql +- yq diff --git a/build b/build index 0544ac3..bf701d3 100644 --- a/build +++ b/build @@ -11,7 +11,7 @@ ReplaceInclude() echo "${2:-}if [ \"\$self\" == \"tv\" ] || [ \"\$self\" == \"iptv\" ]" echo "${2:-}then" ReplaceInclude src/tv " ${2:-}" - bins=(v2 x nx or pve arm ibm cf cx ali lhh rc cw) + bins=(v2 x nx or pve arm ibm cf cx ali lhh rc cw dr) for bin in "${bins[@]}" do echo "${2:-}elif [ \"\$self\" == \"$bin\" ]" diff --git a/core b/core index 8af0639..0c992eb 100644 --- a/core +++ b/core @@ -272,17 +272,11 @@ WaitTerm() } Include utils/system "$@" - Include utils/inquirer "$@" - Include utils/spinner "$@" - Include utils/progress "$@" - Include utils/shfile "$@" - Include utils/jq "$@" - +Include utils/git "$@" Include utils/curl "$@" - Include utils/log diff --git a/docs/iptv.sh b/docs/iptv.sh index 734edda..535cc87 100755 --- a/docs/iptv.sh +++ b/docs/iptv.sh @@ -676,10 +676,7 @@ DepsInstall() # based on https://raw.githubusercontent.com/tanhauhau/Inquirer.sh/master/dist/inquirer.sh inquirer() { - if [[ ! -x $(command -v tput) ]] - then - DepInstall tput - fi + DepInstall tput inquirer:print() { tput el @@ -2214,6 +2211,7 @@ inquirer() if [ "$list_count" -eq 1 ] then inquirer:print "${green}?${normal} ${bold}${bg_black}${white}${prompt} ${bg_black}${cyan}${list_options[current_index]}${normal}\n" + page_list=("${list_options[@]}") return fi @@ -2460,11 +2458,12 @@ inquirer() trap inquirer:control_c EXIT - stty -echo - tput cnorm + #stty -echo + #tput cnorm - inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii - read -r ${var_name?} <<< "$text_input" + read -e text_input + #inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii + read -r ${var_name?} <<< "${text_input:-$text_default}" inquirer:cleanup diff --git a/env b/env index 9a60849..653ca27 100644 --- a/env +++ b/env @@ -28,6 +28,7 @@ ARM_FILE=/usr/local/bin/arm PVE_FILE=/usr/local/bin/pve LOG_FILE="$HOME"/iptv.log JQ_FILE=/usr/local/bin/jq +YQ_FILE=/usr/local/bin/yq FFMPEG_FILE=/usr/local/bin/ffmpeg FFPROBE_FILE=/usr/local/bin/ffprobe CURL_IMPERSONATE_FILE=/usr/local/bin/curl-impersonate @@ -127,3 +128,12 @@ CALIBRE_ROOT="$SERVICES_ROOT"/calibre # Kcc KCC_ROOT="$CALIBRE_ROOT"/kcc KCC_FILE="$KCC_ROOT"/kcc-c2e.py + +# docker +DOCKER_FILE=/usr/local/bin/dr +DOCKER_ROOT="$SERVICES_ROOT"/docker +DOCKER_CONFIG="$SERVICES_ROOT"/docker/docker-compose.yml + +# aios +AIOS_LINK=https://github.com/woniuzfb/iptv +AIOS_ROOT="$SERVICES_ROOT"/aios diff --git a/iptv.sh b/iptv.sh index 734edda..535cc87 100755 --- a/iptv.sh +++ b/iptv.sh @@ -676,10 +676,7 @@ DepsInstall() # based on https://raw.githubusercontent.com/tanhauhau/Inquirer.sh/master/dist/inquirer.sh inquirer() { - if [[ ! -x $(command -v tput) ]] - then - DepInstall tput - fi + DepInstall tput inquirer:print() { tput el @@ -2214,6 +2211,7 @@ inquirer() if [ "$list_count" -eq 1 ] then inquirer:print "${green}?${normal} ${bold}${bg_black}${white}${prompt} ${bg_black}${cyan}${list_options[current_index]}${normal}\n" + page_list=("${list_options[@]}") return fi @@ -2460,11 +2458,12 @@ inquirer() trap inquirer:control_c EXIT - stty -echo - tput cnorm + #stty -echo + #tput cnorm - inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii - read -r ${var_name?} <<< "$text_input" + read -e text_input + #inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii + read -r ${var_name?} <<< "${text_input:-$text_default}" inquirer:cleanup diff --git a/make b/make index 8caffc6..34b99a1 100755 --- a/make +++ b/make @@ -1,5 +1,5 @@ #!/bin/bash -# LianHuanHua / Rclone / Alist / Calibre / FFmpeg / Nginx / Openresty / V2ray / Xray / Cloudflare / IBM Cloud Foundry / Armbian / Proxmox VE / ... +# Docker / LianHuanHua / Rclone / Alist / Calibre / FFmpeg / Nginx / Openresty / V2ray / Xray / Cloudflare / IBM Cloud Foundry / Armbian / Proxmox VE / ... # Copyright (C) 2019-2024 # Released under GPL Version 3 License diff --git a/scripts/build.sh b/scripts/build.sh index ecd5d60..393250a 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1548,6 +1548,7 @@ inquirer() if [ "$list_count" -eq 1 ] then inquirer:print "${green}?${normal} ${bold}${bg_black}${white}${prompt} ${bg_black}${cyan}${list_options[current_index]}${normal}\n" + page_list=("${list_options[@]}") return fi @@ -1794,11 +1795,12 @@ inquirer() trap inquirer:control_c EXIT - stty -echo - tput cnorm + #stty -echo + #tput cnorm - inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii - read -r ${var_name?} <<< "$text_input" + read -e text_input + #inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii + read -r ${var_name?} <<< "${text_input:-$text_default}" inquirer:cleanup diff --git a/scripts/docker/certs/openssl.cnf b/scripts/docker/certs/openssl.cnf new file mode 100644 index 0000000..c20d536 --- /dev/null +++ b/scripts/docker/certs/openssl.cnf @@ -0,0 +1,385 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# Note that you can include other files from the main configuration +# file using the .include directive. +#.include filename + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# System default +openssl_conf = default_conf + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = . # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +unique_subject = no # Set to 'no' to allow creation of + # several certs with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/root.crt # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/root.key # The private key + +x509_extensions = usr_cert # The extensions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = serverkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request +subjectKeyIdentifier = hash +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names +nsComment = "OpenSSL Generated Certificate" + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +basicConstraints = critical,CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ signing_policy ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ signing_req ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment + +[alt_names] +DNS.1 = example.com +DNS.2 = *.example.com +IP.1 = 127.0.0.1 +IP.2 = ::1 + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = . # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/tsakey.pem # The TSA private key (optional) +signer_digest = sha256 # Signing digest to use. (Optional) +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) +ess_cert_id_alg = sha1 # algorithm to compute certificate + # identifier (optional, default: sha1) +[default_conf] +ssl_conf = ssl_sect + +[ssl_sect] +system_default = system_default_sect + +[system_default_sect] +MinProtocol = TLSv1.2 +CipherString = DEFAULT@SECLEVEL=2 diff --git a/scripts/docker/data/authelia/config/configuration.yml b/scripts/docker/data/authelia/config/configuration.yml new file mode 100644 index 0000000..4d3f660 --- /dev/null +++ b/scripts/docker/data/authelia/config/configuration.yml @@ -0,0 +1,77 @@ +--- +############################################################### +# Authelia configuration # +############################################################### + +server: + address: tcp://:9091 + endpoints: + authz: + forward-auth: + implementation: ForwardAuth + +log: + level: error + file_path: /var/log/authelia/authelia.log + +totp: + issuer: authelia.com + +identity_validation: + reset_password: + jwt_secret: ${AUTHELIA_JWT_SECRET_FILE} + +authentication_backend: + file: + path: /config/users_database.yml + +access_control: + default_policy: deny + rules: + - domain: public.${DOMAIN} + policy: bypass + - domain: traefik.${DOMAIN} + policy: one_factor + - domain: secure.${DOMAIN} + policy: two_factor + +session: + secret: ${AUTHELIA_SESSION_SECRET_FILE} + + cookies: + - name: authelia_session + domain: ${DOMAIN} + authelia_url: https://authelia.${DOMAIN} + default_redirection_url: https://public.${DOMAIN} + expiration: '1 hour' + inactivity: '5 minutes' + + redis: + host: redis + port: 6379 + password: ${AUTHELIA_SESSION_REDIS_PASSWORD_FILE} + +regulation: + max_retries: 3 + find_time: '2 minutes' + ban_time: '5 minutes' + +storage: + encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE} + postgres: + address: tcp://127.0.0.1:5432 + database: authelia + schema: public + username: authelia + password: ${AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE} + timeout: 5s + +notifier: + filesystem: + filename: /config/notification.txt + # smtp: + # username: test + # password: ${AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE} + # address: smtp://mail.exmaple.com:25 + # sender: admin@${DOMAIN} +... diff --git a/scripts/docker/data/authelia/config/users_database.yml b/scripts/docker/data/authelia/config/users_database.yml new file mode 100644 index 0000000..92ed75f --- /dev/null +++ b/scripts/docker/data/authelia/config/users_database.yml @@ -0,0 +1,20 @@ +--- +############################################################### +# Users Database # +############################################################### + +# This file can be used if you do not have an LDAP set up. + +# List of users +users: + : + disabled: false + displayname: "" + password: "" + # # Password is authelia + # password: "$6$rounds=50000$BpLnfgDsc2WD8F2q$Zis.ixdg9s/UOJYrs56b5QEZFiZECu0qZVNsIYxBaNJ7ucIL.nlxVCT5tqh8KHG8X4tlwCFm5r6NTOZZ5qRFN/" + email: @${DOMAIN} + groups: + - admins + - dev +... diff --git a/scripts/docker/data/authelia/secrets/JWT_SECRET b/scripts/docker/data/authelia/secrets/JWT_SECRET new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docker/data/authelia/secrets/SESSION_REDIS_PASSWORD b/scripts/docker/data/authelia/secrets/SESSION_REDIS_PASSWORD new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docker/data/authelia/secrets/SESSION_SECRET b/scripts/docker/data/authelia/secrets/SESSION_SECRET new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docker/data/authelia/secrets/STORAGE_ENCRYPTION_KEY b/scripts/docker/data/authelia/secrets/STORAGE_ENCRYPTION_KEY new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docker/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD b/scripts/docker/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docker/data/traefik/config/dynamic.yml b/scripts/docker/data/traefik/config/dynamic.yml new file mode 100644 index 0000000..155eb12 --- /dev/null +++ b/scripts/docker/data/traefik/config/dynamic.yml @@ -0,0 +1,110 @@ +tls: + certificates: + - certFile: /certs/hub.docker.com.crt + keyFile: /certs/hub.docker.com.key + stores: + default: + defaultCertificate: + certFile: /certs/${DOMAIN}.crt + keyFile: /certs/${DOMAIN}.key + +http: + routers: + pianomarvel: + entryPoints: + - websecure + rule: "Host(`pianomvl.${DOMAIN}`)" + service: noop@internal + tls: {} + middlewares: + - CorsPreflight + - pianomarvel + + docker: + entryPoints: + - websecure + rule: "Host(`hub.docker.com`)" + service: noop@internal + tls: {} + middlewares: + - docker-redirect + + xbox-redirect-1-http: + entryPoints: + - web + rule: "HostRegexp(`{subdomain:(assets1|assets2|d1|d2|xvcf1|xvcf2)}.xboxlive.com`)" + service: noop@internal + middlewares: + - CorsPreflight + - xbox-redirect-1 + + xbox-redirect-1-https: + entryPoints: + - websecure + rule: "HostRegexp(`{subdomain:(assets1|assets2|d1|d2|xvcf1|xvcf2)}.xboxlive.com`)" + service: noop@internal + tls: {} + middlewares: + - CorsPreflight + - xbox-redirect-1 + + xbox-redirect-2-http: + entryPoints: + - web + rule: "HostRegexp(`{subdomain:(dlassets|dlassets2)}.xboxlive.com`)" + service: noop@internal + middlewares: + - CorsPreflight + - xbox-redirect-2 + + xbox-redirect-2-https: + entryPoints: + - websecure + rule: "HostRegexp(`{subdomain:(dlassets|dlassets2)}.xboxlive.com`)" + service: noop@internal + tls: {} + middlewares: + - CorsPreflight + - xbox-redirect-2 + + middlewares: + CorsPreflight: + plugin: + CorsPreflight: + code: 204 + method: OPTIONS + + pianomarvel: + redirectRegex: + regex: "^https://(.*).${DOMAIN}/(.*)" + replacement: "http://127.0.0.1:3000/api.pianomarvel.com/$2" + permanent: true + + authelia: + forwardauth: + address: "http://authelia:9091/api/authz/forward-auth" + trustForwardHeader: true + authResponseHeaders: + - Remote-User + - Remote-Groups + - Remote-Name + - Remote-Email + + docker-redirect: + redirectRegex: + regex: "^https://hub.docker.com/(.*)" + replacement: "http://pngquant.com/ffmpeg/docker/$1" + permanent: true + + xbox-redirect-1: + redirectRegex: + regex: "^http://(.*).xboxlive.com/(.*)" + replacement: "http://$1.xboxlive.cn/$2" + permanent: true + + xbox-redirect-2: + redirectRegex: + regex: "^http://(.*).xboxlive.com/(.*)" + replacement: "http://dlassets.xboxlive.cn/$2" + permanent: true + diff --git a/scripts/docker/data/traefik/config/traefik.yml b/scripts/docker/data/traefik/config/traefik.yml new file mode 100644 index 0000000..5a38b5a --- /dev/null +++ b/scripts/docker/data/traefik/config/traefik.yml @@ -0,0 +1,58 @@ +providers: + docker: {} + file: + directory: /etc/traefik + filename: dynamic.yml + watch: true + +log: + level: ERROR + filePath: /var/log/traefik/traefik.log + +entryPoints: + web: + address: :80 + proxyProtocol: + insecure: false + trustedIPs: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - fc00::/7 + forwardedHeaders: + insecure: false + trustedIPs: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - fc00::/7 + + websecure: + address: :443 + proxyProtocol: + insecure: false + trustedIPs: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - fc00::/7 + forwardedHeaders: + insecure: false + trustedIPs: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - fc00::/7 + +api: + dashboard: true + insecure: true + +testData: + code: 200 + method: OPTIONS + +experimental: + localPlugins: + CorsPreflight: + modulename: github.com/Medzoner/traefik-plugin-cors-preflight diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml new file mode 100644 index 0000000..dbab42c --- /dev/null +++ b/scripts/docker/docker-compose.yml @@ -0,0 +1,138 @@ +name: aios + +networks: + net: + driver: bridge + +secrets: + JWT_SECRET: + file: ${PWD}/data/authelia/secrets/JWT_SECRET + SESSION_SECRET: + file: ${PWD}/data/authelia/secrets/SESSION_SECRET + SESSION_REDIS_PASSWORD: + file: ${PWD}/data/authelia/secrets/SESSION_REDIS_PASSWORD + STORAGE_POSTGRES_PASSWORD: + file: ${PWD}/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD + STORAGE_ENCRYPTION_KEY: + file: ${PWD}/data/authelia/secrets/STORAGE_ENCRYPTION_KEY + +services: + traefik: + image: traefik:latest + container_name: traefik + networks: + net: + aliases: [] + ports: + - 80:80 + - 443:443 + - 8080:8080 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ${PWD}/data/traefik/config:/etc/traefik + - ${PWD}/data/traefik/logs:/var/log/traefik + - ${PWD}/data/traefik/plugins-local:/plugins-local + - ${PWD}/certs/traefik:/certs + environment: + DOMAIN: example.com + labels: + - traefik.enable=true + - traefik.http.routers.api.rule=Host(`traefik.${DOMAIN}`) + - traefik.http.routers.api.entrypoints=websecure + - traefik.http.routers.api.service=api@internal + - traefik.http.routers.api.tls=true + - traefik.http.routers.api.middlewares=authelia@docker + + whoami: + image: "traefik/whoami" + container_name: whoami + restart: unless-stopped + networks: + - net + expose: + - 80 + environment: + DOMAIN: example.com + labels: + - traefik.enable=true + - 'traefik.http.routers.whoami.rule=Host(`traefik.${DOMAIN}`) && Path(`/whoami`)' + + secure: + image: traefik/whoami + container_name: secure + restart: unless-stopped + networks: + - net + expose: + - 80 + labels: + - traefik.enable=true + - traefik.http.routers.secure.rule=Host(`secure.${DOMAIN}`) + - traefik.http.routers.secure.entrypoints=websecure + - traefik.http.routers.secure.tls=true + - traefik.http.routers.secure.middlewares=authelia@docker + + public: + image: traefik/whoami + container_name: public + restart: unless-stopped + networks: + - net + expose: + - 80 + labels: + - traefik.enable=true + - traefik.http.routers.secure.rule=Host(`public.${DOMAIN}`) + - traefik.http.routers.secure.entrypoints=websecure + - traefik.http.routers.secure.tls=true + + authelia: + image: docker.io/authelia/authelia:latest + container_name: authelia + restart: unless-stopped + networks: + net: + aliases: [] + expose: + - 9091 + # ports: + # - 127.0.0.1:9091:9091 + volumes: + - ${PWD}/data/authelia/config:/config + - ${PWD}/data/authelia/logs:/var/log/authelia + secrets: + - JWT_SECRET + - SESSION_SECRET + - SESSION_REDIS_PASSWORD + - STORAGE_POSTGRES_PASSWORD + - STORAGE_ENCRYPTION_KEY + environment: + AUTHELIA_JWT_SECRET_FILE: /run/secrets/JWT_SECRET + AUTHELIA_SESSION_SECRET_FILE: /run/secrets/SESSION_SECRET + AUTHELIA_SESSION_REDIS_PASSWORD_FILE: /run/secrets/SESSION_REDIS_PASSWORD + AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: /run/secrets/STORAGE_POSTGRES_PASSWORD + AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /run/secrets/STORAGE_ENCRYPTION_KEY + TZ: Asia/Shanghai + DOMAIN: example.com + labels: + - traefik.enable=true + - traefik.http.routers.authelia.rule=Host(`authelia.${DOMAIN}`) + - traefik.http.routers.authelia.entrypoints=websecure + - traefik.http.routers.authelia.tls=true + - traefik.http.routers.authelia.middlewares=authelia + + redis: + image: redis:alpine + container_name: redis + volumes: + - ${PWD}/data/redis:/data + networks: + - net + expose: + - 6379 + restart: unless-stopped + secrets: + - SESSION_REDIS_PASSWORD + environment: + TZ: Asia/Shanghai + command: /bin/sh -c 'redis-server --requirepass $$(< /run/secrets/SESSION_REDIS_PASSWORD)' diff --git a/src/calibre/kcc b/src/calibre/kcc index dfcd1a0..6674b5d 100644 --- a/src/calibre/kcc +++ b/src/calibre/kcc @@ -7,7 +7,7 @@ KccInstall() Println "$info KCC 更新成功\n" return 0 fi - DepInstall git + GitInstall PythonInstall git clone https://github.com/ciromattia/kcc.git "$KCC_ROOT" cd "$KCC_ROOT" diff --git a/src/calibre/web b/src/calibre/web index ce06b03..193277b 100644 --- a/src/calibre/web +++ b/src/calibre/web @@ -8,7 +8,7 @@ CalibreWebInstall() return fi - DepInstall git + GitInstall PythonInstall git clone https://github.com/janeczku/calibre-web.git "$CALIBRE_ROOT/web" cd "$CALIBRE_ROOT/web" diff --git a/src/docker/crt b/src/docker/crt new file mode 100644 index 0000000..cf739cf --- /dev/null +++ b/src/docker/crt @@ -0,0 +1,120 @@ +DockerCrtSelfSignValid() +{ + local domain=$1 + + if [ -e "$service_cert_root/$domain".crt ] && [ -e "$service_cert_root/$domain".key ] + then + return 1 + fi +} + +DockerCrtManage() +{ + if [ ! -d "$DOCKER_ROOT" ] + then + if [ ! -d "$AIOS_ROOT" ] + then + GitInstall + git clone "$AIOS_LINK" "$AIOS_ROOT" + else + cd "$AIOS_ROOT" + git pull + fi + cp -r "$AIOS_ROOT"/scripts/docker "$DOCKER_ROOT" + fi + + echo + crt_options=( '浏览证书' '安装自签名证书' ) + inquirer list_input_index "选择操作" crt_options crt_options_index + + case $crt_options_index in + 0) ServiceBrowse "$DOCKER_ROOT"/certs + ;; + 1) + cd "$DOCKER_ROOT"/certs + + if [ ! -f "$DOCKER_ROOT"/certs/root.crt ] + then + echo + inquirer text_input "请输入你想设置的根证书公用名CN (Common Name)" root_cn root.yourdomain.com + openssl req -new -nodes -text -out root.csr -newkey rsa:4096 -keyout root.key -subj "/CN=$root_cn" + chmod og-rwx root.key + openssl x509 -req -in root.csr -text -days 3650 -extfile "$DOCKER_ROOT"/certs/openssl.cnf -extensions v3_ca -signkey root.key -out root.crt + Println "$info "$DOCKER_ROOT"/certs/root.crt 可以添加到用户端系统用来验证之后自签名的证书\n" + fi + + docker_certs_services=( 'traefik' ) + echo + inquirer list_input "选择安装证书的服务" docker_certs_services docker_certs_service + + service_cert_root="$DOCKER_ROOT/certs/$docker_certs_service" + + mkdir -p newcerts + mkdir -p "$docker_certs_service" + + echo + inquirer text_input "请输入自签名证书公用名CN (Common Name)" server_cn localhost DockerCrtSelfSignValid "证书已存在" + + ny_index=0 + + if ! [[ "$server_cn" =~ \* ]] + then + echo + inquirer list_input_index "是否将子域名 *.$server_cn 加到 SAN" ny_options ny_index + fi + + if [ "$ny_index" -eq 1 ] + then + root_domain="${server_cn#\*.}" + san="DNS:$root_domain,DNS:*.$root_domain,IP:127.0.0.1,IP:::1" + else + san="DNS:$server_cn,IP:127.0.0.1,IP:::1" + fi + + openssl req -new -nodes -text -out "$service_cert_root/${server_cn}".csr -newkey rsa:4096 -keyout "$service_cert_root/${server_cn}".key -subj "/CN=$server_cn" -addext "subjectAltName=$san" + + chmod og-rwx "$service_cert_root/${server_cn}".key + + if openssl help x509 2>&1 | grep -q "copy_extensions" + then + openssl_cmds=(openssl x509 -req -copy_extensions copy -in "$service_cert_root/${server_cn}".csr -text -days 365 -CA root.crt -CAkey root.key -CAcreateserial -out "$service_cert_root/${server_cn}".crt) + else + openssl_cmds=(openssl ca -batch -config "$DOCKER_ROOT"/certs/openssl.cnf -policy signing_policy -extensions signing_req -out "$service_cert_root/${server_cn}".crt -infiles "$service_cert_root/${server_cn}".csr) + fi + + if [ ! -f ./index.txt ] + then + touch index.txt + fi + + if [ ! -f ./serial ] + then + echo 01 > serial + fi + + "${openssl_cmds[@]}" + + openssl x509 -in "$service_cert_root/${server_cn}".crt -outform PEM -out "$service_cert_root/${server_cn}".pem + + if [ "$ny_index" -eq 1 ] + then + openssl req -new -nodes -text -out "$service_cert_root/*.${server_cn}".csr -newkey rsa:4096 -keyout "$service_cert_root/*.${server_cn}".key -subj "/CN=*.$server_cn" -addext "subjectAltName=$san" + chmod og-rwx "$service_cert_root/*.${server_cn}".key + if openssl help x509 2>&1 | grep -q "copy_extensions" + then + openssl_cmds=(openssl x509 -req -copy_extensions copy -in "$service_cert_root/*.${server_cn}".csr -text -days 365 -CA ../root.crt -CAkey ../root.key -CAcreateserial -out "$service_cert_root/*.${server_cn}".crt) + else + openssl_cmds=(openssl ca -batch -config "$DOCKER_ROOT"/certs/openssl.cnf -policy signing_policy -extensions signing_req -out "$service_cert_root/*.${server_cn}".crt -infiles "$service_cert_root/*.${server_cn}".csr) + fi + "${openssl_cmds[@]}" + openssl x509 -in "$service_cert_root/*.${server_cn}".crt -outform PEM -out "$service_cert_root/*.${server_cn}".pem + cat "$service_cert_root/${server_cn}".pem "$service_cert_root/*.${server_cn}".pem > "$service_cert_root/${server_cn}".pem.tmp + mv "$service_cert_root/${server_cn}".pem.tmp "$service_cert_root/${server_cn}".pem + fi + + Println "$info 自签名证书安装成功\n" + ;; + esac + + return 0 +} diff --git a/src/docker/install b/src/docker/install index a095d72..395082c 100644 --- a/src/docker/install +++ b/src/docker/install @@ -2,7 +2,7 @@ DockerInstall() { local install="更新" - if [ -z "${2:-}" ] + if [ -z "${1:-}" ] then if [[ -x $(command -v docker) ]] then @@ -36,11 +36,11 @@ DockerInstall() then curl -fsSL http://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + $(. /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list else curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + $(. /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list fi sudo apt-get update fi @@ -61,11 +61,11 @@ DockerInstall() then curl -fsSL http://mirrors.ustc.edu.cn/docker-ce/linux/debian/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list else curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list fi sudo apt-get update fi diff --git a/src/docker/service b/src/docker/service new file mode 100644 index 0000000..fb9f20c --- /dev/null +++ b/src/docker/service @@ -0,0 +1,300 @@ +DockerServiceStart() +{ + DockerInstall + PostgresqlInstall + YqInstall + + traefik_domain=$(yq .services.traefik.environment.DOMAIN "$DOCKER_CONFIG") + + if [ ! -f "$DOCKER_ROOT/certs/traefik/$traefik_domain".crt ] || [ ! -f "$DOCKER_ROOT/certs/traefik/$traefik_domain".key ] + then + Println "$error $traefik_domain 的证书不存在\n" + return 1 + fi + + if [ ! -f "$DOCKER_ROOT"/certs/traefik/hub.docker.com.crt ] || [ ! -f "$DOCKER_ROOT"/certs/traefik/hub.docker.com.key ] + then + Println "$error hub.docker.com 的证书不存在\n" + return 1 + fi + + traefik_local_plugins=($(yq '.experimental.localPlugins | map_values(.modulename) | to_entries | .[] | .value' "$DOCKER_ROOT"/data/traefik/config/traefik.yml)) + + for traefik_local_plugin in "${traefik_local_plugins[@]}" + do + if [ ! -d "$DOCKER_ROOT/data/traefik/plugins-local/src/$traefik_local_plugin" ] + then + Println "$error traefik 本地插件 $traefik_local_plugin 不存在, 请先设置\n" + return 1 + fi + done + + JWT_SECRET=$(< "$DOCKER_ROOT"/data/authelia/secrets/JWT_SECRET) + SESSION_REDIS_PASSWORD=$(< "$DOCKER_ROOT"/data/authelia/secrets/SESSION_REDIS_PASSWORD) + SESSION_SECRET=$(< "$DOCKER_ROOT"/data/authelia/secrets/SESSION_SECRET) + STORAGE_ENCRYPTION_KEY=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_ENCRYPTION_KEY) + STORAGE_POSTGRES_PASSWORD=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD) + + for var in JWT_SECRET SESSION_REDIS_PASSWORD SESSION_SECRET STORAGE_ENCRYPTION_KEY STORAGE_POSTGRES_PASSWORD + do + if [[ -z "${!var:-}" ]] + then + Println "$error $var 为空, 请先设置服务 secrets\n" + return 1 + fi + done + + if ! psql -c "\du" | grep -q authelia || ! psql -c "SELECT datname FROM pg_catalog.pg_database;" | grep -q authelia + then + Println "$error 请先设置服务 postgresql\n" + return 1 + fi + + cd "$DOCKER_ROOT" + + mkdir -p "$DOCKER_ROOT/data/redis" + mkdir -p "$DOCKER_ROOT/data/traefik/logs" + mkdir -p "$DOCKER_ROOT/data/authelia/logs" + + docker compose up -d +} + +DockerServiceStop() +{ + DockerInstall + + cd "$DOCKER_ROOT" + + docker compose stop +} + +DockerServiceConfig() +{ + echo + docker_config_options=( 'Traefik' 'Authelia' 'Postgresql' ) + inquirer checkbox_input_indices "请选择" docker_config_options docker_config_options_indices + + for docker_config_options_index in "${docker_config_options_indices[@]}" + do + echo + case $docker_config_options_index in + 0) + traefik_options=( '域名' '本地插件' ) + inquirer list_input_index "选择 traefik 设置选项" traefik_options traefik_options_index + if [ $traefik_options_index -eq 0 ] + then + traefik_default_domain=$(yq .services.traefik.environment.DOMAIN "$DOCKER_CONFIG") + echo + inquirer text_input "请输入 traefik 使用的域名" traefik_domain "$traefik_default_domain" + if [ "$traefik_domain" != "$traefik_default_domain" ] + then + yq -i '.services.traefik.environment.DOMAIN = strenv(traefik_domain)' "$DOCKER_CONFIG" + Println "$info traefik 域名已设置为 $traefik_domain\n" + fi + else + traefik_local_plugins=( cors-preflight ) + traefik_plugins=( github.com/Medzoner/traefik-plugin-cors-preflight ) + echo + inquirer checkbox_input_indices "选择 traefik 本地插件" traefik_local_plugins traefik_local_plugins_indices + for traefik_local_plugins_index in "${traefik_local_plugins_indices[@]}" + do + if [ -d "$DOCKER_ROOT/data/traefik/plugins-local/src/${traefik_plugins[$traefik_local_plugins_index]}" ] + then + cd "$DOCKER_ROOT/data/traefik/plugins-local/src/${traefik_plugins[$traefik_local_plugins_index]}" + git pull + Println "$info ${traefik_local_plugins[$traefik_local_plugins_index]} 插件已更新\n" + continue + fi + git clone "https://${traefik_plugins[$traefik_local_plugins_index]}" "$DOCKER_ROOT/data/traefik/plugins-local/src/${traefik_plugins[$traefik_local_plugins_index]}" + Println "$info ${traefik_local_plugins[$traefik_local_plugins_index]} 插件已下载\n" + done + fi + ;; + 1) + authelia_options=( '域名' '用户名' '显示名' '密码' secrets ) + inquirer list_input_indices "选择 authelia 设置选项" authelia_options authelia_options_indices + for authelia_options_index in "${authelia_options_indices[@]}" + do + case $authelia_options_index in + 0) + authelia_default_domain=$(yq .services.authelia.environment.DOMAIN "$DOCKER_CONFIG") + echo + inquirer text_input "请输入 authelia 使用的域名" authelia_domain "$authelia_default_domain" + if [ "$authelia_domain" != "$authelia_default_domain" ] + then + yq -i '.services.authelia.environment.DOMAIN = strenv(authelia_domain)' "$DOCKER_CONFIG" + echo + inquirer list_input "是否添加到 /etc/hosts" ny_options ny_index + if [ $ny_index -eq 1 ] + then + Println "$tip 可能需要输入密码" + echo "\ +127.0.0.1 hub.docker.com +127.0.0.1 authelia.$DOMAIN +127.0.0.1 public.$DOMAIN +127.0.0.1 traefik.$DOMAIN +127.0.0.1 secure.$DOMAIN" | sudo tee -a /etc/hosts > /dev/null + fi + Println "$info authelia 域名已设置为 $authelia_domain\n" + fi + ;; + 1) + authelia_usernames=($(yq '.users | keys | join(" ")' "$DOCKER_ROOT"/data/authelia/config/users_database.yml)) + authelia_default_username="${authelia_usernames[0]}" + echo + inquirer text_input "请输入 authelia 用户名" authelia_username "$authelia_default_username" + if [ "$authelia_username" != "$authelia_default_username" ] + then + yq -i '.users.strenv(authelia_username) = .users.strenv(authelia_default_username) | del(.users.strenv(authelia_default_username))' "$DOCKER_ROOT"/data/authelia/config/users_database.yml + authelia_user_email=$(yq '.users.strenv(authelia_username).email' "$DOCKER_ROOT"/data/authelia/config/users_database.yml) + if [ "$authelia_user_email" == '@${DOMAIN}' ] + then + yq -i '.users.strenv(authelia_username).email = strenv(authelia_username) + "@${DOMAIN}"' "$DOCKER_ROOT"/data/authelia/config/users_database.yml + fi + Println "$info authelia 用户名已改为 $authelia_username\n" + fi + ;; + 2) + authelia_usernames=($(yq '.users | keys | join(" ")' "$DOCKER_ROOT"/data/authelia/config/users_database.yml)) + authelia_default_username="${authelia_usernames[0]}" + authelia_default_displayname=$(yq '.users.strenv(authelia_default_username).displayname' "$DOCKER_ROOT"/data/authelia/config/users_database.yml) + echo + inquirer text_input "请输入 authelia 用户 $authelia_default_username 的显示名" authelia_displayname "$authelia_default_displayname" + if [ "$authelia_displayname" != "$authelia_default_displayname" ] + then + yq -i '.users.strenv(authelia_default_username).displayname = strenv(authelia_displayname)' "$DOCKER_ROOT"/data/authelia/config/users_database.yml + Println "$info authelia 用户 $authelia_default_username 的显示名已改为 $authelia_displayname\n" + fi + ;; + 3) + authelia_usernames=($(yq '.users | keys | join(" ")' "$DOCKER_ROOT"/data/authelia/config/users_database.yml)) + authelia_default_username="${authelia_usernames[0]}" + authelia_default_password=$(yq '.users.strenv(authelia_default_username).password' "$DOCKER_ROOT"/data/authelia/config/users_database.yml) + DockerInstall + if ! docker images | grep -q authelia/authelia + then + docker pull authelia/authelia + fi + echo + inquirer text_input "请输入 authelia 用户 $authelia_default_username 的密码" authelia_password "$authelia_default_password" + authelia_password=$(docker run authelia/authelia authelia crypto hash generate argon2 --password $authelia_password | sed 's/Digest: //g') + if [ "$authelia_password" != "$authelia_default_password" ] + then + yq -i '.users.strenv(authelia_default_username).password = strenv(authelia_password)' "$DOCKER_ROOT"/data/authelia/config/users_database.yml + Println "$info authelia 用户 $authelia_default_username 的密码已改为 $authelia_password\n" + fi + ;; + 4) + authelia_secrets=( JWT_SECRET SESSION_REDIS_PASSWORD SESSION_SECRET STORAGE_ENCRYPTION_KEY STORAGE_POSTGRES_PASSWORD ) + echo + inquirer checkbox_input_indices "选择设置的 secret" authelia_secrets authelia_secrets_indices + + for authelia_secret_index in "${authelia_secrets_indices[@]}" + do + echo + case $authelia_secret_index in + 0) + default_jwt_secret=$(< "$DOCKER_ROOT"/data/authelia/secrets/JWT_SECRET) + inquirer text_input "请输入 JWT_SECRET" JWT_SECRET "${default_jwt_secret:-$(openssl rand -hex 32)}" + ;; + 1) + default_session_redis_password=$(< "$DOCKER_ROOT"/data/authelia/secrets/SESSION_REDIS_PASSWORD) + inquirer text_input "请输入 SESSION_REDIS_PASSWORD" SESSION_REDIS_PASSWORD "${default_session_redis_password:-$(RandStr 15)}" + ;; + 2) + default_session_secret=$(< "$DOCKER_ROOT"/data/authelia/secrets/SESSION_SECRET) + inquirer text_input "请输入 SESSION_SECRET" SESSION_SECRET "${default_session_secret:-$(openssl rand -hex 64)}" + ;; + 3) + default_storage_encryption_key=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_ENCRYPTION_KEY) + inquirer text_input "请输入 STORAGE_ENCRYPTION_KEY" STORAGE_ENCRYPTION_KEY "${default_storage_encryption_key:-$(openssl rand -hex 32)}" + ;; + 4) + default_storage_postgres_password=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD) + inquirer text_input "请输入 STORAGE_POSTGRES_PASSWORD" STORAGE_POSTGRES_PASSWORD "${default_storage_postgres_password:-$(RandStr 15)}" + ;; + esac + echo "${!authelia_secrets[authelia_secret_index]}" > "$DOCKER_ROOT"/data/authelia/secrets/${authelia_secrets[authelia_secret_index]} + Println "$info ${authelia_secrets[authelia_secret_index]} 设置成功\n" + done + ;; + esac + done + ;; + 2) + postgresql_options=( '添加 role authelia' '添加 database authelia' '设置 role authelia 的密码' ) + echo + inquirer checkbox_input_indices "选择 postgresql 设置选项" postgresql_options postgresql_options_indices + for postgresql_options_index in "${postgresql_options_indices[@]}" + do + case $postgresql_options_index in + 0) + if psql -c "\du" | grep -q authelia + then + Println "$error role authelia 已存在\n" + continue + fi + default_storage_postgres_password=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD) + echo + inquirer text_input "请输入 role authelia 的密码" storage_postgres_password "${default_storage_postgres_password:-$(RandStr 15)}" + psql -c "CREATE ROLE authelia PASSWORD '$storage_postgres_password' CREATEDB REPLICATION LOGIN;" + Println "$info role authelia 已添加\n" + ;; + 1) + if ! psql -c "\du" | grep -q authelia + then + Println "$error 请先添加 role authelia\n" + continue + fi + if psql -c "SELECT datname FROM pg_catalog.pg_database;" | grep -q authelia + then + Println "$error database authelia 已存在\n" + continue + fi + psql -c "CREATE DATABASE authelia OWNER authelia;" + Println "$info database authelia 已添加\n" + ;; + 2) + if ! psql -c "\du" | grep -q authelia + then + Println "$error 请先添加 role authelia\n" + continue + fi + default_storage_postgres_password=$(< "$DOCKER_ROOT"/data/authelia/secrets/STORAGE_POSTGRES_PASSWORD) + echo + inquirer text_input "请输入 role authelia 的密码" storage_postgres_password "${default_storage_postgres_password:-$(RandStr 15)}" + psql -c "ALTER ROLE authelia PASSWORD '$storage_postgres_password';" + Println "$info role authelia 的密码已设置\n" + ;; + esac + done + ;; + esac + done + + return 0 +} + +DockerService() +{ + docker_service_options=( '启动' '关闭' '重启' '设置' ) + echo + inquirer list_input_index "请选择" docker_service_options docker_service_options_index + + case $docker_service_options_index in + 0) DockerServiceStart + ;; + 1) DockerServiceStop + ;; + 2) + DockerServiceStop + DockerServiceStart + ;; + 3) + YqInstall + DockerServiceConfig + ;; + esac + + return 0 +} diff --git a/src/dr b/src/dr index fa11a6a..124279e 100644 --- a/src/dr +++ b/src/dr @@ -1 +1,23 @@ +Include src/docker/install "$@" +Include src/docker/crt "$@" +Include utils/postgresql "$@" +Include utils/yq "$@" + +DepInstall sudo + +docker_options=( '服务' '管理证书' '安装/更新 docker' '安装/更新 postgresql' '安装/更新 yq' ) echo +inquirer list_input_index "请选择" docker_options docker_options_index + +case $docker_options_index in + 0) DockerService + ;; + 1) DockerCrtManage + ;; + 2) DockerInstall update + ;; + 3) PostgresqlInstall update + ;; + 4) YqInstall update + ;; +esac diff --git a/src/nginx/add_domain b/src/nginx/add_domain index 68544dd..f45ffae 100644 --- a/src/nginx/add_domain +++ b/src/nginx/add_domain @@ -50,7 +50,7 @@ NginxAddDomain() Println "$info $server_domain 配置成功\n" ;; 1) - NginxSitesCertInstall "$server_domain" + NginxSitesCrtInstall "$server_domain" inquirer list_input "是否设置 http 跳转 https" yn_options http_to_https_yn if [ "$http_to_https_yn" == "$i18n_yes" ] @@ -81,7 +81,7 @@ NginxAddDomain() Println "$info $server_domain 配置成功\n" ;; 2) - NginxSitesCertInstall "$server_domain" + NginxSitesCrtInstall "$server_domain" inquirer list_input "http 和 https 是否使用相同的目录" yn_options http_https_same_dir_yn if [ "$http_https_same_dir_yn" == "$i18n_yes" ] diff --git a/src/nginx/config_nodejs b/src/nginx/config_nodejs index 6eb9605..4835c86 100644 --- a/src/nginx/config_nodejs +++ b/src/nginx/config_nodejs @@ -160,10 +160,7 @@ app.listen(port, () => console.log(\`App listening on port \${port}!\`)) } }' > "$NODE_ROOT/package.json" - if [[ ! -x $(command -v git) ]] - then - Spinner "安装 git" GitInstall - fi + GitInstall cd "$NODE_ROOT" npm install diff --git a/src/nginx/sites_crt b/src/nginx/sites_crt index a6f9fe0..025c87b 100644 --- a/src/nginx/sites_crt +++ b/src/nginx/sites_crt @@ -1,4 +1,4 @@ -NginxSitesCertInstall() +NginxSitesCrtInstall() { local domain=$1 @@ -33,6 +33,16 @@ NginxSitesCertInstall() Println "$info $domain 证书安装成功\n" } +NginxSitesCrtSelfSignValid() +{ + local domain=$1 + + if [ -e "$cert_root/$domain".crt ] && [ -e "$cert_root/$domain".key ] + then + return 1 + fi +} + NginxSitesCrtManage() { if [ ! -d "$nginx_prefix"/conf/sites_crt ] @@ -42,7 +52,7 @@ NginxSitesCrtManage() fi echo - crt_options=( '查看证书' '安装本地证书' '安装域名证书' ) + crt_options=( '浏览证书' '安装自签名证书' '安装ACME证书' ) inquirer list_input_index "选择操作" crt_options crt_options_index case $crt_options_index in @@ -50,10 +60,91 @@ NginxSitesCrtManage() ;; 1) cd "$nginx_prefix"/conf/sites_crt - openssl genrsa -out localhost.key 2048 - openssl req -subj "/C=US/ST=NULL/L=NULL/O=NULL/OU=NULL/CN=NULL/emailAddress=NULL@example.com" -new -key localhost.key -out localhost.csr - openssl x509 -req -days 3650 -in localhost.csr -signkey localhost.key -out localhost.crt - Println "$info 本地证书安装成功\n" + + if [ ! -f "$nginx_prefix"/conf/sites_crt/openssl.cnf ] + then + if ! curl -Lm 20 -o "$nginx_prefix"/conf/sites_crt/openssl.cnf "$FFMPEG_MIRROR_LINK"/openssl.cnf + then + Println "$error 下载 openssl.cnf 失败, 请稍后再试\n" + return 1 + fi + fi + + if [ ! -f "$nginx_prefix"/conf/sites_crt/root.crt ] + then + echo + inquirer text_input "请输入你想设置的根证书公用名CN (Common Name)" root_cn root.yourdomain.com + openssl req -new -nodes -text -out root.csr -newkey rsa:4096 -keyout root.key -subj "/CN=$root_cn" + chmod og-rwx root.key + openssl x509 -req -in root.csr -text -days 3650 -extfile "$nginx_prefix"/conf/sites_crt/openssl.cnf -extensions v3_ca -signkey root.key -out root.crt + Println "$info "$nginx_prefix"/conf/root.crt 可以添加到用户端系统用来验证之后自签名的证书\n" + fi + + cert_root="$nginx_prefix"/conf/sites_crt + + mkdir -p newcerts + + echo + inquirer text_input "请输入自签名证书公用名CN (Common Name)" server_cn localhost NginxSitesCrtSelfSignValid "证书已存在" + + ny_index=0 + + if ! [[ "$server_cn" =~ \* ]] + then + echo + inquirer list_input_index "是否将子域名 *.$server_cn 加到 SAN" ny_options ny_index + fi + + if [ "$ny_index" -eq 1 ] + then + root_domain="${server_cn#\*.}" + san="DNS:$root_domain,DNS:*.$root_domain,IP:127.0.0.1,IP:::1" + else + san="DNS:$server_cn,IP:127.0.0.1,IP:::1" + fi + + openssl req -new -nodes -text -out "$cert_root/${server_cn}".csr -newkey rsa:4096 -keyout "$cert_root/${server_cn}".key -subj "/CN=$server_cn" -addext "subjectAltName=$san" + + chmod og-rwx "$cert_root/${server_cn}".key + + if openssl help x509 2>&1 | grep -q "copy_extensions" + then + openssl_cmds=(openssl x509 -req -copy_extensions copy -in "$cert_root/${server_cn}".csr -text -days 365 -CA root.crt -CAkey root.key -CAcreateserial -out "$cert_root/${server_cn}".crt) + else + openssl_cmds=(openssl ca -batch -config "$nginx_prefix"/conf/sites_crt/openssl.cnf -policy signing_policy -extensions signing_req -out "$cert_root/${server_cn}".crt -infiles "$cert_root/${server_cn}".csr) + fi + + if [ ! -f ./index.txt ] + then + touch index.txt + fi + + if [ ! -f ./serial ] + then + echo 01 > serial + fi + + "${openssl_cmds[@]}" + + openssl x509 -in "$cert_root/${server_cn}".crt -outform PEM -out "$cert_root/${server_cn}".pem + + if [ "$ny_index" -eq 1 ] + then + openssl req -new -nodes -text -out "$cert_root/*.${server_cn}".csr -newkey rsa:4096 -keyout "$cert_root/*.${server_cn}".key -subj "/CN=*.$server_cn" -addext "subjectAltName=$san" + chmod og-rwx '*'.${server_cn}.key + if openssl help x509 2>&1 | grep -q "copy_extensions" + then + openssl_cmds=(openssl x509 -req -copy_extensions copy -in "$cert_root/*.${server_cn}".csr -text -days 365 -CA ../root.crt -CAkey ../root.key -CAcreateserial -out "$cert_root/*.${server_cn}".crt) + else + openssl_cmds=(openssl ca -batch -config "$nginx_prefix"/conf/sites_crt/openssl.cnf -policy signing_policy -extensions signing_req -out "$cert_root/*.${server_cn}".crt -infiles "$cert_root/*.${server_cn}".csr) + fi + "${openssl_cmds[@]}" + openssl x509 -in "$cert_root/*.${server_cn}".crt -outform PEM -out "$cert_root/*.${server_cn}".pem + cat "$cert_root/${server_cn}".pem "$cert_root/*.${server_cn}".pem > "$cert_root/${server_cn}".pem.tmp + mv "$cert_root/${server_cn}".pem.tmp "$cert_root/${server_cn}".pem + fi + + Println "$info 自签名证书安装成功\n" ;; 2) NginxConfigDomain ;; diff --git a/src/nx b/src/nx index 8a7af47..154aff3 100644 --- a/src/nx +++ b/src/nx @@ -4,7 +4,6 @@ Include utils/openssl "$@" Include utils/go "$@" Include utils/postfix "$@" Include utils/tesseract "$@" -Include utils/git "$@" Include utils/nodejs "$@" Include utils/mongodb "$@" Include utils/dnscrypt "$@" diff --git a/src/or b/src/or index 5ef87f7..de749e6 100644 --- a/src/or +++ b/src/or @@ -4,7 +4,6 @@ Include utils/openssl "$@" Include utils/go "$@" Include utils/postfix "$@" Include utils/tesseract "$@" -Include utils/git "$@" Include utils/nodejs "$@" Include utils/mongodb "$@" Include utils/dnscrypt "$@" diff --git a/src/pve b/src/pve index f5dc107..fd62054 100644 --- a/src/pve +++ b/src/pve @@ -1,13 +1,8 @@ Include utils/apt "$@" - Include utils/vim "$@" - Include utils/dnscrypt "$@" - Include src/proxmox/get_vms "$@" - Include src/proxmox/list_vms "$@" - Include src/proxmox/select_vm "$@" if [[ ! -x $(command -v pveum) ]] @@ -260,7 +255,7 @@ case $pve_num in then Println "$info 安装 nbfc..." - DepInstall git + GitInstall DepInstall curl DepInstall unzip diff --git a/src/tv b/src/tv index edffffc..13b9245 100644 --- a/src/tv +++ b/src/tv @@ -5,7 +5,6 @@ Include utils/openssl "$@" Include utils/pdf2html "$@" Include utils/imagemagick "$@" Include utils/imgcat "$@" -Include utils/git "$@" Include utils/nodejs "$@" Include utils/mongodb "$@" Include src/iptv/filter_string "$@" diff --git a/utils/curl b/utils/curl index 86e2030..0ef1ed2 100644 --- a/utils/curl +++ b/utils/curl @@ -190,7 +190,7 @@ CurlImpersonateCompile() echo inquirer text_input "输入 curl-impersonate 安装目录" curl_impersonate_prefix /usr/local/curl-impersonate - DepInstall git + GitInstall cd ~ diff --git a/utils/git b/utils/git index dce5074..4cafc61 100644 --- a/utils/git +++ b/utils/git @@ -1,15 +1,25 @@ GitInstall() { - if [ "$dist" == "rpm" ] + if [[ -x $(command -v git) ]] then - yum -y install git > /dev/null - elif [ "$dist" == "ubu" ] - then - add-apt-repository ppa:git-core/ppa -y > /dev/null - AptUpdate - apt-get -y install git > /dev/null - else - apt-get -y install git > /dev/null + return 0 fi - Println "$info git 安装成功...\n" + + Println "$info 安装 git" + + case $dist in + mac) brew install git + ;; + rpm) yum -y install git + ;; + deb) apt-get -y install git + ;; + ubu) + add-apt-repository ppa:git-core/ppa -y + apt-get -y update + apt-get -y install git + ;; + esac + + Println "$info git 安装成功\n" } diff --git a/utils/inquirer b/utils/inquirer index b3e0425..982098d 100644 --- a/utils/inquirer +++ b/utils/inquirer @@ -1,10 +1,7 @@ # based on https://raw.githubusercontent.com/tanhauhau/Inquirer.sh/master/dist/inquirer.sh inquirer() { - if [[ ! -x $(command -v tput) ]] - then - DepInstall tput - fi + DepInstall tput inquirer:print() { tput el @@ -1539,6 +1536,7 @@ inquirer() if [ "$list_count" -eq 1 ] then inquirer:print "${green}?${normal} ${bold}${bg_black}${white}${prompt} ${bg_black}${cyan}${list_options[current_index]}${normal}\n" + page_list=("${list_options[@]}") return fi @@ -1785,11 +1783,12 @@ inquirer() trap inquirer:control_c EXIT - stty -echo - tput cnorm + #stty -echo + #tput cnorm - inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii - read -r ${var_name?} <<< "$text_input" + read -e text_input + #inquirer:on_keypress inquirer:on_default inquirer:on_default inquirer:on_text_input_ascii inquirer:on_text_input_enter inquirer:on_text_input_left inquirer:on_text_input_right inquirer:on_text_input_ascii inquirer:on_text_input_backspace inquirer:on_text_input_not_ascii + read -r ${var_name?} <<< "${text_input:-$text_default}" inquirer:cleanup diff --git a/utils/iperf b/utils/iperf index 7a340f9..09f1ea1 100644 --- a/utils/iperf +++ b/utils/iperf @@ -4,7 +4,7 @@ IperfInstall() { local install="更新" - if [ -z "${2:-}" ] + if [ -z "${1:-}" ] then if [[ -x $(command -v iperf3) ]] then diff --git a/utils/postgresql b/utils/postgresql new file mode 100644 index 0000000..8b0b809 --- /dev/null +++ b/utils/postgresql @@ -0,0 +1,160 @@ +PostgresqlInstall() +{ + local install="更新" + + if [ -z "${1:-}" ] + then + if [[ -x $(command -v psql) ]] + then + return 0 + fi + install="安装" + elif [[ ! -x $(command -v psql) ]] + then + install="安装" + fi + + if [ "$dist" == "mac" ] + then + brew install --cask postgres-unofficial + open /Applications/Postgres.app + if [ ! -f /etc/paths.d/postgresapp ] + then + Println "$info 输入密码配置命令行: " + sudo mkdir -p /etc/paths.d && echo /Applications/Postgres.app/Contents/Versions/latest/bin | sudo tee /etc/paths.d/postgresapp + fi + Println "$info postgresql ${install}成功\n" + return 0 + fi + + DepInstall curl + DepInstall ca-certificates + + . /etc/os-release + + case $dist in + ubu) + if ! [[ "$VERSION_CODENAME" =~ mantic|lunar|jammy|focal ]] + then + sudo apt-get -y install postgresql-12 + return 0 + fi + if [ ! -f /etc/apt/sources.list.d/pgdg.list ] + then + if grep -q "mirrors.ustc.edu.cn" < /etc/apt/sources.list + then + curl -fsSL https://mirrors.ustc.edu.cn/postgresql/repos/apt/ACCC4CF8.asc | gpg --batch --yes --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] https://mirrors.ustc.edu.cn/postgresql/repos/apt \ + ${VERSION_CODENAME:-$UBUNTU_CODENAME}-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list > /dev/null + else + curl -fsSL https://mirrors.ustc.edu.cn/postgresql/repos/apt/ACCC4CF8.asc | gpg --batch --yes --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] https://apt.postgresql.org/pub/repos/apt \ + ${VERSION_CODENAME:-$UBUNTU_CODENAME}-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list > /dev/null + fi + sudo apt-get update + fi + sudo apt-get -y install postgresql + ;; + deb) + if ! [[ "$VERSION_CODENAME" =~ bookworm|bullseye|buster|sid ]] + then + sudo apt-get -y install postgresql-12 + return 0 + fi + if [ ! -f /etc/apt/sources.list.d/pgdg.list ] + then + if grep -q "mirrors.ustc.edu.cn" < /etc/apt/sources.list + then + curl -fsSL https://mirrors.ustc.edu.cn/postgresql/repos/apt/ACCC4CF8.asc | gpg --batch --yes --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] https://mirrors.ustc.edu.cn/postgresql/repos/apt \ + ${VERSION_CODENAME}-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list + else + curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --batch --yes --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] https://apt.postgresql.org/pub/repos/apt \ + ${VERSION_CODENAME}-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list + fi + sudo apt-get update + fi + sudo apt-get -y install postgresql + ;; + rpm) + ArchCheck + . /etc/os-release + local repo_name="" + if [ "$arch" == "arm64" ] + then + repo_name="-aarch64" + else + repo_name="-x86_64" + fi + if [ "${ID:-}" == "fedora" ] + then + repo_name="F-${VERSION_ID%%.*}${repo_name}/pgdg-fedora-repo-latest.noarch.rpm" + else + repo_name="EL-${VERSION_ID%%.*}${repo_name}/pgdg-redhat-repo-latest.noarch.rpm" + fi + if [[ -x $(command -v dnf) ]] + then + sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/${repo_name} + sudo dnf -qy module disable postgresql || true + sudo dnf install -y postgresql16-server + sudo /usr/pgsql-16/bin/postgresql-16-setup initdb + sudo systemctl enable postgresql-16 + sudo systemctl start postgresql-16 + else + sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/${repo_name}/pgdg-redhat-repo-latest.noarch.rpm + sudo yum install -y postgresql16-server + if [ "${VERSION_ID%%.*}" -eq 7 ] + then + sudo /usr/pgsql-16/bin/postgresql-16-setup initdb + sudo systemctl enable postgresql-16 + sudo systemctl start postgresql-16 + else + sudo service postgresql-16 initdb + sudo chkconfig postgresql-16 on + sudo service postgresql-16 start + fi + fi + ;; + opensuse) + zypper install -l -y postgresql16-server + systemctl enable postgresql.service + systemctl start postgresql.service + ;; + sles) + . /etc/os-release + if [ "${VERSION_ID%%.*}" -eq 12 ] + then + SUSEConnect -p PackageHub/12/x86_64 + SUSEConnect -p sle-sdk/12/x86_64 + zypper addrepo https://download.postgresql.org/pub/repos/zypp/repo/pgdg-sles-12-pg15.repo + zypper refresh + zypper install postgresql15-server + else + zypper addrepo https://download.opensuse.org/repositories/devel:/libraries:/c_c++/${VERSION_ID}/devel:libraries:c_c++.repo + zypper addrepo https://download.opensuse.org/repositories/science/${VERSION_ID}/science.repo + zypper addrepo https://download.opensuse.org/repositories/Application:/Geo/${VERSION_ID}/Application:Geo.repo + SUSEConnect -p sle-module-desktop-applications/${VERSION_ID}/x86_64 + SUSEConnect -p PackageHub/${VERSION_ID}/x86_64 + zypper --gpg-auto-import-keys install -y zypper install https://download.postgresql.org/pub/repos/zypp/reporpms/SLES-15-x86_64/pgdg-suse-repo-latest.noarch.rpm + zypper refresh + zypper install postgresql16-server + fi + + systemctl enable postgresql.service + systemctl start postgresql.service + ;; + *) + Println "$error 不支持的系统\n" + return 1 + ;; + esac + + if ! su postgres -c 'psql -c "\du"' | grep -q "$USER" + then + su postgres -c "createuser --superuser $USER" + createdb "$USER" + fi + + Println "$info postgresql 安装成功\n" +} diff --git a/utils/shfile b/utils/shfile index 67cc323..f8986fa 100644 --- a/utils/shfile +++ b/utils/shfile @@ -109,6 +109,7 @@ ShFileCheck() [ ! -e "$LIANHUANHUA_FILE" ] && ln -s "$SH_FILE" "$LIANHUANHUA_FILE" [ ! -e "$RCLONE_FILE" ] && ln -s "$SH_FILE" "$RCLONE_FILE" [ ! -e "$CALIBRE_FILE" ] && ln -s "$SH_FILE" "$CALIBRE_FILE" + [ ! -e "$DOCKER_FILE" ] && ln -s "$SH_FILE" "$DOCKER_FILE" return 0 } diff --git a/utils/system b/utils/system index a9e5a28..1e66946 100644 --- a/utils/system +++ b/utils/system @@ -12,11 +12,7 @@ DistCheck() continue fi - if grep -Eqi "Red Hat|redhat|CentOS|Fedora|Amazon" < "$dist_file" - then - dist="rpm" - break - elif grep -qi "Ubuntu" < "$dist_file" + if grep -qi "Ubuntu" < "$dist_file" then dist="ubu" break @@ -24,6 +20,10 @@ DistCheck() then dist="deb" break + elif grep -Eqi "Red Hat|redhat|rhel|CentOS|Fedora|Amazon" < "$dist_file" + then + dist="rpm" + break fi done @@ -34,7 +34,7 @@ DistCheck() dist="mac" else Println "${red}[ERROR]${normal} not support yet...\n" - exit 1 + return 1 fi fi } @@ -312,7 +312,7 @@ DepsInstall() setenforce 0 fi - depends=(wget unzip vim curl crond logrotate patch nscd) + depends=(sudo wget unzip vim curl crond logrotate patch nscd) if [[ ! -x $(command -v dig) ]] then @@ -354,7 +354,7 @@ DepsInstall() apt-get -y install ca-certificates >/dev/null 2>&1 - depends=(wget unzip vim curl cron ufw python3 logrotate patch nscd) + depends=(sudo wget unzip vim curl cron ufw python3 logrotate patch nscd) if [[ ! -x $(command -v dig) ]] then diff --git a/utils/tesseract b/utils/tesseract index 56c4b17..9e92401 100644 --- a/utils/tesseract +++ b/utils/tesseract @@ -11,7 +11,7 @@ TesseractInstall() if [ "$dist" == "ubu" ] then add-apt-repository ppa:alex-p/tesseract-ocr -y - AptUpdate + apt-get -y update apt-get -y install tesseract elif [ "$dist" == "deb" ] then diff --git a/utils/vim b/utils/vim index 52d6073..0e23604 100644 --- a/utils/vim +++ b/utils/vim @@ -30,7 +30,7 @@ set expandtab autocmd BufRead,BufNewFile *.conf setfiletype conf filetype indent off EOF - DepInstall git + GitInstall Println "$info vimrc 设置完成, 请在 vim 下执行 PlugInstall\n" else Println "$error 无法连接服务器, 请稍后再试\n" diff --git a/utils/yq b/utils/yq new file mode 100644 index 0000000..0875eed --- /dev/null +++ b/utils/yq @@ -0,0 +1,62 @@ +YqInstall() +{ + local install="更新" + + if [ -z "${1:-}" ] + then + if [[ -x $(command -v yq) ]] + then + return 0 + fi + install="安装" + elif [[ ! -x $(command -v yq) ]] + then + install="安装" + fi + + DepsCheck + ArchCheck + + if [ "$dist" == "mac" ] + then + echo + inquirer list_input_index "是否编译(brew安装可能会很慢)" ny_options ny_index + if [ "$ny_index" -eq 1 ] + then + brew install yq + Println "$info yq ${install}成功\n" + return 0 + fi + if [ "$arch" == "x86_64" ] + then + yq_name=yq_darwin_amd64 + else + yq_name=yq_darwin_arm64 + fi + else + case $arch in + i386) yq_name=yq_linux_386 + ;; + x86_64) yq_name=yq_linux_amd64 + ;; + arm64|s390x) yq_name=yq_linux_$arch + ;; + arm*) yq_name=yq_linux_arm + ;; + *) Println "不支持的架构: $arch"; return 1 + ;; + esac + fi + + if curl -L "$FFMPEG_MIRROR_LINK/yq/$yq_name" -o "$YQ_FILE"_tmp + then + mv "$YQ_FILE"_tmp "$YQ_FILE" + chmod +x "$YQ_FILE" + else + rm -f "$YQ_FILE"_tmp + Println "`eval_gettext \"\\\$error 下载 yq 失败, 请重试 !\"`" + return 1 + fi + + Println "$info yq ${install}成功\n" +}