mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'bookworm' into portal-api
This commit is contained in:
commit
db30b3acb8
70 changed files with 889 additions and 936 deletions
|
@ -7,7 +7,6 @@ generate-helpers-doc:
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get update -y && apt-get install git hub -y
|
|
||||||
- git config --global user.email "yunohost@yunohost.org"
|
- git config --global user.email "yunohost@yunohost.org"
|
||||||
- git config --global user.name "$GITHUB_USER"
|
- git config --global user.name "$GITHUB_USER"
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -3,34 +3,33 @@
|
||||||
########################################
|
########################################
|
||||||
# later we must fix lint and format-check jobs and remove "allow_failure"
|
# later we must fix lint and format-check jobs and remove "allow_failure"
|
||||||
|
|
||||||
lint39:
|
lint311:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- tox -e py39-lint
|
- tox -e py311-lint
|
||||||
|
|
||||||
invalidcode39:
|
invalidcode311:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
- tox -e py39-invalidcode
|
- tox -e py311-invalidcode
|
||||||
|
|
||||||
mypy:
|
mypy:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
- tox -e py39-mypy
|
- tox -e py311-mypy
|
||||||
|
|
||||||
black:
|
black:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get update -y && apt-get install git hub -y
|
|
||||||
- git config --global user.email "yunohost@yunohost.org"
|
- git config --global user.email "yunohost@yunohost.org"
|
||||||
- git config --global user.name "$GITHUB_USER"
|
- git config --global user.name "$GITHUB_USER"
|
||||||
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
|
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
|
||||||
|
@ -38,7 +37,7 @@ black:
|
||||||
script:
|
script:
|
||||||
# create a local branch that will overwrite distant one
|
# create a local branch that will overwrite distant one
|
||||||
- git checkout -b "ci-format-${CI_COMMIT_REF_NAME}" --no-track
|
- git checkout -b "ci-format-${CI_COMMIT_REF_NAME}" --no-track
|
||||||
- tox -e py39-black-run
|
- tox -e py311-black-run
|
||||||
- '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
|
- '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
|
||||||
- git commit -am "[CI] Format code with Black" || true
|
- git commit -am "[CI] Format code with Black" || true
|
||||||
- git push -f origin "ci-format-${CI_COMMIT_REF_NAME}":"ci-format-${CI_COMMIT_REF_NAME}"
|
- git push -f origin "ci-format-${CI_COMMIT_REF_NAME}":"ci-format-${CI_COMMIT_REF_NAME}"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
.install_debs: &install_debs
|
.install_debs: &install_debs
|
||||||
- apt-get update -o Acquire::Retries=3
|
- apt-get update -o Acquire::Retries=3
|
||||||
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
|
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
|
||||||
- pip3 install -U mock pip pytest pytest-cov pytest-mock pytest-sugar requests-mock tox ansi2html black jinja2 "packaging<22"
|
|
||||||
|
|
||||||
.test-stage:
|
.test-stage:
|
||||||
stage: test
|
stage: test
|
||||||
|
|
|
@ -16,7 +16,6 @@ autofix-translated-strings:
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get update -y && apt-get install git hub -y
|
|
||||||
- git config --global user.email "yunohost@yunohost.org"
|
- git config --global user.email "yunohost@yunohost.org"
|
||||||
- git config --global user.name "$GITHUB_USER"
|
- git config --global user.name "$GITHUB_USER"
|
||||||
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
|
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
|
||||||
|
|
|
@ -132,12 +132,8 @@ def main() -> bool:
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
|
# Broadcast IPv4 and IPv6
|
||||||
# Buster only ships 0.1.6
|
ips: List[str] = interfaces[interface]["ipv4"] + interfaces[interface]["ipv6"]
|
||||||
# Bullseye ships 0.1.7
|
|
||||||
# To be re-enabled once we're on bullseye...
|
|
||||||
# ips: List[str] = interfaces[interface]["ipv4"] + interfaces[interface]["ipv6"]
|
|
||||||
ips: List[str] = interfaces[interface]["ipv4"]
|
|
||||||
|
|
||||||
# If at least one IP is listed
|
# If at least one IP is listed
|
||||||
if not ips:
|
if not ips:
|
||||||
|
|
|
@ -13,9 +13,8 @@ protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %}
|
||||||
mail_plugins = $mail_plugins quota notify push_notification
|
mail_plugins = $mail_plugins quota notify push_notification
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# generated 2023-06-13, Mozilla Guideline v5.7, Dovecot 2.3.19, OpenSSL 3.0.9, intermediate configuration
|
||||||
# generated 2020-08-18, Mozilla Guideline v5.6, Dovecot 2.3.4, OpenSSL 1.1.1d, intermediate configuration
|
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.19&config=intermediate&openssl=3.0.9&guideline=5.7
|
||||||
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.4&config=intermediate&openssl=1.1.1d&guideline=5.6
|
|
||||||
|
|
||||||
ssl = required
|
ssl = required
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ ssl_dh = </usr/share/yunohost/ffdhe2048.pem
|
||||||
|
|
||||||
# intermediate configuration
|
# intermediate configuration
|
||||||
ssl_min_protocol = TLSv1.2
|
ssl_min_protocol = TLSv1.2
|
||||||
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
|
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
||||||
ssl_prefer_server_ciphers = no
|
ssl_prefer_server_ciphers = no
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
# See man 5 jail.conf for details.
|
# See man 5 jail.conf for details.
|
||||||
#
|
#
|
||||||
# [DEFAULT]
|
# [DEFAULT]
|
||||||
# bantime = 3600
|
# bantime = 1h
|
||||||
#
|
#
|
||||||
# [sshd]
|
# [sshd]
|
||||||
# enabled = true
|
# enabled = true
|
||||||
|
@ -44,10 +44,52 @@ before = paths-debian.conf
|
||||||
# MISCELLANEOUS OPTIONS
|
# MISCELLANEOUS OPTIONS
|
||||||
#
|
#
|
||||||
|
|
||||||
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
|
# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
|
||||||
# ban a host which matches an address in this list. Several addresses can be
|
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
|
||||||
# defined using space (and/or comma) separator.
|
#bantime.increment = true
|
||||||
ignoreip = 127.0.0.1/8
|
|
||||||
|
# "bantime.rndtime" is the max number of seconds using for mixing with random time
|
||||||
|
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
|
||||||
|
#bantime.rndtime =
|
||||||
|
|
||||||
|
# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
|
||||||
|
#bantime.maxtime =
|
||||||
|
|
||||||
|
# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
|
||||||
|
# default value of factor is 1 and with default value of formula, the ban time
|
||||||
|
# grows by 1, 2, 4, 8, 16 ...
|
||||||
|
#bantime.factor = 1
|
||||||
|
|
||||||
|
# "bantime.formula" used by default to calculate next value of ban time, default value below,
|
||||||
|
# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
|
||||||
|
#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
|
||||||
|
#
|
||||||
|
# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
|
||||||
|
#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)
|
||||||
|
|
||||||
|
# "bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
|
||||||
|
# previously ban count and given "bantime.factor" (for multipliers default is 1);
|
||||||
|
# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
|
||||||
|
# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
|
||||||
|
#bantime.multipliers = 1 2 4 8 16 32 64
|
||||||
|
# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
|
||||||
|
# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
|
||||||
|
#bantime.multipliers = 1 5 30 60 300 720 1440 2880
|
||||||
|
|
||||||
|
# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed
|
||||||
|
# cross over all jails, if false (default), only current jail of the ban IP will be searched
|
||||||
|
#bantime.overalljails = false
|
||||||
|
|
||||||
|
# --------------------
|
||||||
|
|
||||||
|
# "ignoreself" specifies whether the local resp. own IP addresses should be ignored
|
||||||
|
# (default is true). Fail2ban will not ban a host which matches such addresses.
|
||||||
|
#ignoreself = true
|
||||||
|
|
||||||
|
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
|
||||||
|
# will not ban a host which matches an address in this list. Several addresses
|
||||||
|
# can be defined using space (and/or comma) separator.
|
||||||
|
#ignoreip = 127.0.0.1/8 ::1
|
||||||
|
|
||||||
# External command that will take an tagged arguments to ignore, e.g. <ip>,
|
# External command that will take an tagged arguments to ignore, e.g. <ip>,
|
||||||
# and return true if the IP is to be ignored. False otherwise.
|
# and return true if the IP is to be ignored. False otherwise.
|
||||||
|
@ -56,15 +98,18 @@ ignoreip = 127.0.0.1/8
|
||||||
ignorecommand =
|
ignorecommand =
|
||||||
|
|
||||||
# "bantime" is the number of seconds that a host is banned.
|
# "bantime" is the number of seconds that a host is banned.
|
||||||
bantime = 600
|
bantime = 10m
|
||||||
|
|
||||||
# A host is banned if it has generated "maxretry" during the last "findtime"
|
# A host is banned if it has generated "maxretry" during the last "findtime"
|
||||||
# seconds.
|
# seconds.
|
||||||
findtime = 600
|
findtime = 10m
|
||||||
|
|
||||||
# "maxretry" is the number of failures before a host get banned.
|
# "maxretry" is the number of failures before a host get banned.
|
||||||
maxretry = 10
|
maxretry = 10
|
||||||
|
|
||||||
|
# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
|
||||||
|
maxmatches = %(maxretry)s
|
||||||
|
|
||||||
# "backend" specifies the backend used to get files modification.
|
# "backend" specifies the backend used to get files modification.
|
||||||
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
|
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
|
||||||
# This option can be overridden in each jail as well.
|
# This option can be overridden in each jail as well.
|
||||||
|
@ -113,10 +158,13 @@ logencoding = auto
|
||||||
enabled = false
|
enabled = false
|
||||||
|
|
||||||
|
|
||||||
|
# "mode" defines the mode of the filter (see corresponding filter implementation for more info).
|
||||||
|
mode = normal
|
||||||
|
|
||||||
# "filter" defines the filter to use by the jail.
|
# "filter" defines the filter to use by the jail.
|
||||||
# By default jails have names matching their filter name
|
# By default jails have names matching their filter name
|
||||||
#
|
#
|
||||||
filter = %(__name__)s
|
filter = %(__name__)s[mode=%(mode)s]
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -140,7 +188,7 @@ mta = sendmail
|
||||||
# Default protocol
|
# Default protocol
|
||||||
protocol = tcp
|
protocol = tcp
|
||||||
|
|
||||||
# Specify chain where jumps would need to be added in iptables-* actions
|
# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
|
||||||
chain = INPUT
|
chain = INPUT
|
||||||
|
|
||||||
# Ports to be banned
|
# Ports to be banned
|
||||||
|
@ -161,51 +209,53 @@ banaction = iptables-multiport
|
||||||
banaction_allports = iptables-allports
|
banaction_allports = iptables-allports
|
||||||
|
|
||||||
# The simplest action to take: ban only
|
# The simplest action to take: ban only
|
||||||
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||||
|
|
||||||
# ban & send an e-mail with whois report to the destemail.
|
# ban & send an e-mail with whois report to the destemail.
|
||||||
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
action_mw = %(action_)s
|
||||||
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||||
|
|
||||||
# ban & send an e-mail with whois report and relevant log lines
|
# ban & send an e-mail with whois report and relevant log lines
|
||||||
# to the destemail.
|
# to the destemail.
|
||||||
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
action_mwl = %(action_)s
|
||||||
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||||
|
|
||||||
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
||||||
#
|
#
|
||||||
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
||||||
# to the destemail.
|
# to the destemail.
|
||||||
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
action_xarf = %(action_)s
|
||||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
|
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
|
||||||
|
|
||||||
|
# ban & send a notification to one or more of the 50+ services supported by Apprise.
|
||||||
|
# See https://github.com/caronc/apprise/wiki for details on what is supported.
|
||||||
|
#
|
||||||
|
# You may optionally over-ride the default configuration line (containing the Apprise URLs)
|
||||||
|
# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise
|
||||||
|
# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration.
|
||||||
|
# action = %(action_)s
|
||||||
|
# apprise
|
||||||
|
|
||||||
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
|
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
|
||||||
# to the destemail.
|
# to the destemail.
|
||||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||||
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||||
|
|
||||||
# Report block via blocklist.de fail2ban reporting service API
|
# Report block via blocklist.de fail2ban reporting service API
|
||||||
#
|
#
|
||||||
# See the IMPORTANT note in action.d/blocklist_de.conf for when to
|
# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
|
||||||
# use this action. Create a file jail.d/blocklist_de.local containing
|
# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
|
||||||
# [Init]
|
# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
|
||||||
# blocklist_de_apikey = {api key from registration]
|
# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in
|
||||||
|
# corresponding jail.d/my-jail.local file).
|
||||||
#
|
#
|
||||||
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||||
|
|
||||||
# Report ban via badips.com, and use as blacklist
|
# Report ban via abuseipdb.com.
|
||||||
#
|
#
|
||||||
# See BadIPsAction docstring in config/action.d/badips.py for
|
# See action.d/abuseipdb.conf for usage example and details.
|
||||||
# documentation for this action.
|
|
||||||
#
|
#
|
||||||
# NOTE: This action relies on banaction being present on start and therefore
|
action_abuseipdb = abuseipdb
|
||||||
# should be last action defined for a jail.
|
|
||||||
#
|
|
||||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
|
||||||
#
|
|
||||||
# Report ban via badips.com (uses action.d/badips.conf for reporting only)
|
|
||||||
#
|
|
||||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
|
||||||
|
|
||||||
# Choose default action. To change, just override value of 'action' with the
|
# Choose default action. To change, just override value of 'action' with the
|
||||||
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
|
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
|
||||||
|
@ -223,15 +273,10 @@ action = %(action_)s
|
||||||
|
|
||||||
[sshd]
|
[sshd]
|
||||||
|
|
||||||
port = ssh
|
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
|
||||||
logpath = %(sshd_log)s
|
# normal (default), ddos, extra or aggressive (combines all).
|
||||||
backend = %(sshd_backend)s
|
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
|
||||||
|
#mode = normal
|
||||||
|
|
||||||
[sshd-ddos]
|
|
||||||
# This jail corresponds to the standard configuration in Fail2ban.
|
|
||||||
# The mail-whois action send a notification e-mail with a whois request
|
|
||||||
# in the body.
|
|
||||||
port = ssh
|
port = ssh
|
||||||
logpath = %(sshd_log)s
|
logpath = %(sshd_log)s
|
||||||
backend = %(sshd_backend)s
|
backend = %(sshd_backend)s
|
||||||
|
@ -265,7 +310,7 @@ logpath = %(apache_error_log)s
|
||||||
# for email addresses. The mail outputs are buffered.
|
# for email addresses. The mail outputs are buffered.
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = %(apache_access_log)s
|
logpath = %(apache_access_log)s
|
||||||
bantime = 172800
|
bantime = 48h
|
||||||
maxretry = 1
|
maxretry = 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,7 +346,7 @@ maxretry = 2
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = %(apache_access_log)s
|
logpath = %(apache_access_log)s
|
||||||
maxretry = 1
|
maxretry = 1
|
||||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot <ip>
|
||||||
|
|
||||||
|
|
||||||
[apache-modsecurity]
|
[apache-modsecurity]
|
||||||
|
@ -321,12 +366,15 @@ maxretry = 1
|
||||||
[openhab-auth]
|
[openhab-auth]
|
||||||
|
|
||||||
filter = openhab
|
filter = openhab
|
||||||
action = iptables-allports[name=NoAuthFailures]
|
banaction = %(banaction_allports)s
|
||||||
logpath = /opt/openhab/logs/request.log
|
logpath = /opt/openhab/logs/request.log
|
||||||
|
|
||||||
|
|
||||||
|
# To use more aggressive http-auth modes set filter parameter "mode" in jail.local:
|
||||||
|
# normal (default), aggressive (combines all), auth or fallback
|
||||||
|
# See "tests/files/logs/nginx-http-auth" or "filter.d/nginx-http-auth.conf" for usage example and details.
|
||||||
[nginx-http-auth]
|
[nginx-http-auth]
|
||||||
|
# mode = normal
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = %(nginx_error_log)s
|
logpath = %(nginx_error_log)s
|
||||||
|
|
||||||
|
@ -342,8 +390,10 @@ logpath = %(nginx_error_log)s
|
||||||
|
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = %(nginx_error_log)s
|
logpath = %(nginx_error_log)s
|
||||||
maxretry = 2
|
|
||||||
|
|
||||||
|
[nginx-bad-request]
|
||||||
|
port = http,https
|
||||||
|
logpath = %(nginx_access_log)s
|
||||||
|
|
||||||
# Ban attackers that try to use PHP's URL-fopen() functionality
|
# Ban attackers that try to use PHP's URL-fopen() functionality
|
||||||
# through GET/POST variables. - Experimental, with more than a year
|
# through GET/POST variables. - Experimental, with more than a year
|
||||||
|
@ -377,6 +427,8 @@ logpath = %(lighttpd_error_log)s
|
||||||
|
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = %(roundcube_errors_log)s
|
logpath = %(roundcube_errors_log)s
|
||||||
|
# Use following line in your jail.local if roundcube logs to journal.
|
||||||
|
#backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
|
||||||
[openwebmail]
|
[openwebmail]
|
||||||
|
@ -426,11 +478,13 @@ backend = %(syslog_backend)s
|
||||||
|
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = /var/log/tomcat*/catalina.out
|
logpath = /var/log/tomcat*/catalina.out
|
||||||
|
#logpath = /var/log/guacamole.log
|
||||||
|
|
||||||
[monit]
|
[monit]
|
||||||
#Ban clients brute-forcing the monit gui login
|
#Ban clients brute-forcing the monit gui login
|
||||||
port = 2812
|
port = 2812
|
||||||
logpath = /var/log/monit
|
logpath = /var/log/monit
|
||||||
|
/var/log/monit.log
|
||||||
|
|
||||||
|
|
||||||
[webmin-auth]
|
[webmin-auth]
|
||||||
|
@ -513,27 +567,29 @@ logpath = %(vsftpd_log)s
|
||||||
# ASSP SMTP Proxy Jail
|
# ASSP SMTP Proxy Jail
|
||||||
[assp]
|
[assp]
|
||||||
|
|
||||||
port = smtp,submission
|
port = smtp,465,submission
|
||||||
logpath = /root/path/to/assp/logs/maillog.txt
|
logpath = /root/path/to/assp/logs/maillog.txt
|
||||||
|
|
||||||
|
|
||||||
[courier-smtp]
|
[courier-smtp]
|
||||||
|
|
||||||
port = smtp,submission
|
port = smtp,465,submission
|
||||||
logpath = %(syslog_mail)s
|
logpath = %(syslog_mail)s
|
||||||
backend = %(syslog_backend)s
|
backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
|
||||||
[postfix]
|
[postfix]
|
||||||
|
# To use another modes set filter parameter "mode" in jail.local:
|
||||||
port = smtp,submission
|
mode = more
|
||||||
logpath = %(postfix_log)s
|
port = smtp,465,submission
|
||||||
backend = %(postfix_backend)s
|
logpath = %(postfix_log)s
|
||||||
|
backend = %(postfix_backend)s
|
||||||
|
|
||||||
|
|
||||||
[postfix-rbl]
|
[postfix-rbl]
|
||||||
|
|
||||||
port = smtp,submission
|
filter = postfix[mode=rbl]
|
||||||
|
port = smtp,465,submission
|
||||||
logpath = %(postfix_log)s
|
logpath = %(postfix_log)s
|
||||||
backend = %(postfix_backend)s
|
backend = %(postfix_backend)s
|
||||||
maxretry = 1
|
maxretry = 1
|
||||||
|
@ -541,14 +597,17 @@ maxretry = 1
|
||||||
|
|
||||||
[sendmail-auth]
|
[sendmail-auth]
|
||||||
|
|
||||||
port = submission,smtp
|
port = submission,465,smtp
|
||||||
logpath = %(syslog_mail)s
|
logpath = %(syslog_mail)s
|
||||||
backend = %(syslog_backend)s
|
backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
|
||||||
[sendmail-reject]
|
[sendmail-reject]
|
||||||
|
# To use more aggressive modes set filter parameter "mode" in jail.local:
|
||||||
port = smtp,submission
|
# normal (default), extra or aggressive
|
||||||
|
# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details.
|
||||||
|
#mode = normal
|
||||||
|
port = smtp,465,submission
|
||||||
logpath = %(syslog_mail)s
|
logpath = %(syslog_mail)s
|
||||||
backend = %(syslog_backend)s
|
backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
@ -556,7 +615,7 @@ backend = %(syslog_backend)s
|
||||||
[qmail-rbl]
|
[qmail-rbl]
|
||||||
|
|
||||||
filter = qmail
|
filter = qmail
|
||||||
port = smtp,submission
|
port = smtp,465,submission
|
||||||
logpath = /service/qmail/log/main/current
|
logpath = /service/qmail/log/main/current
|
||||||
|
|
||||||
|
|
||||||
|
@ -564,14 +623,14 @@ logpath = /service/qmail/log/main/current
|
||||||
# but can be set by syslog_facility in the dovecot configuration.
|
# but can be set by syslog_facility in the dovecot configuration.
|
||||||
[dovecot]
|
[dovecot]
|
||||||
|
|
||||||
port = pop3,pop3s,imap,imaps,submission,sieve
|
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||||
logpath = %(dovecot_log)s
|
logpath = %(dovecot_log)s
|
||||||
backend = %(dovecot_backend)s
|
backend = %(dovecot_backend)s
|
||||||
|
|
||||||
|
|
||||||
[sieve]
|
[sieve]
|
||||||
|
|
||||||
port = smtp,submission
|
port = smtp,465,submission
|
||||||
logpath = %(dovecot_log)s
|
logpath = %(dovecot_log)s
|
||||||
backend = %(dovecot_backend)s
|
backend = %(dovecot_backend)s
|
||||||
|
|
||||||
|
@ -583,20 +642,21 @@ logpath = %(solidpop3d_log)s
|
||||||
|
|
||||||
|
|
||||||
[exim]
|
[exim]
|
||||||
|
# see filter.d/exim.conf for further modes supported from filter:
|
||||||
port = smtp,submission
|
#mode = normal
|
||||||
|
port = smtp,465,submission
|
||||||
logpath = %(exim_main_log)s
|
logpath = %(exim_main_log)s
|
||||||
|
|
||||||
|
|
||||||
[exim-spam]
|
[exim-spam]
|
||||||
|
|
||||||
port = smtp,submission
|
port = smtp,465,submission
|
||||||
logpath = %(exim_main_log)s
|
logpath = %(exim_main_log)s
|
||||||
|
|
||||||
|
|
||||||
[kerio]
|
[kerio]
|
||||||
|
|
||||||
port = imap,smtp,imaps
|
port = imap,smtp,imaps,465
|
||||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||||
|
|
||||||
|
|
||||||
|
@ -607,14 +667,15 @@ logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||||
|
|
||||||
[courier-auth]
|
[courier-auth]
|
||||||
|
|
||||||
port = smtp,submission,imaps,pop3,pop3s
|
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||||
logpath = %(syslog_mail)s
|
logpath = %(syslog_mail)s
|
||||||
backend = %(syslog_backend)s
|
backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
|
||||||
[postfix-sasl]
|
[postfix-sasl]
|
||||||
|
|
||||||
port = smtp,submission,imap,imaps,pop3,pop3s
|
filter = postfix[mode=auth]
|
||||||
|
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||||
# You might consider monitoring /var/log/mail.warn instead if you are
|
# You might consider monitoring /var/log/mail.warn instead if you are
|
||||||
# running postfix since it would provide the same log lines at the
|
# running postfix since it would provide the same log lines at the
|
||||||
# "warn" level but overall at the smaller filesize.
|
# "warn" level but overall at the smaller filesize.
|
||||||
|
@ -631,7 +692,7 @@ backend = %(syslog_backend)s
|
||||||
|
|
||||||
[squirrelmail]
|
[squirrelmail]
|
||||||
|
|
||||||
port = smtp,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||||
|
|
||||||
|
|
||||||
|
@ -684,8 +745,8 @@ logpath = /var/log/named/security.log
|
||||||
[nsd]
|
[nsd]
|
||||||
|
|
||||||
port = 53
|
port = 53
|
||||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||||
logpath = /var/log/nsd.log
|
logpath = /var/log/nsd.log
|
||||||
|
|
||||||
|
|
||||||
|
@ -696,9 +757,8 @@ logpath = /var/log/nsd.log
|
||||||
[asterisk]
|
[asterisk]
|
||||||
|
|
||||||
port = 5060,5061
|
port = 5060,5061
|
||||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||||
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
|
|
||||||
logpath = /var/log/asterisk/messages
|
logpath = /var/log/asterisk/messages
|
||||||
maxretry = 10
|
maxretry = 10
|
||||||
|
|
||||||
|
@ -706,16 +766,22 @@ maxretry = 10
|
||||||
[freeswitch]
|
[freeswitch]
|
||||||
|
|
||||||
port = 5060,5061
|
port = 5060,5061
|
||||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||||
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
|
|
||||||
logpath = /var/log/freeswitch.log
|
logpath = /var/log/freeswitch.log
|
||||||
maxretry = 10
|
maxretry = 10
|
||||||
|
|
||||||
|
|
||||||
|
# enable adminlog; it will log to a file inside znc's directory by default.
|
||||||
|
[znc-adminlog]
|
||||||
|
|
||||||
|
port = 6667
|
||||||
|
logpath = /var/lib/znc/moddata/adminlog/znc.log
|
||||||
|
|
||||||
|
|
||||||
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
|
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
|
||||||
# equivalent section:
|
# equivalent section:
|
||||||
# log-warning = 2
|
# log-warnings = 2
|
||||||
#
|
#
|
||||||
# for syslog (daemon facility)
|
# for syslog (daemon facility)
|
||||||
# [mysqld_safe]
|
# [mysqld_safe]
|
||||||
|
@ -731,6 +797,14 @@ logpath = %(mysql_log)s
|
||||||
backend = %(mysql_backend)s
|
backend = %(mysql_backend)s
|
||||||
|
|
||||||
|
|
||||||
|
[mssql-auth]
|
||||||
|
# Default configuration for Microsoft SQL Server for Linux
|
||||||
|
# See the 'mssql-conf' manpage how to change logpath or port
|
||||||
|
logpath = /var/opt/mssql/log/errorlog
|
||||||
|
port = 1433
|
||||||
|
filter = mssql-auth
|
||||||
|
|
||||||
|
|
||||||
# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
|
# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
|
||||||
[mongodb-auth]
|
[mongodb-auth]
|
||||||
# change port when running with "--shardsvr" or "--configsvr" runtime operation
|
# change port when running with "--shardsvr" or "--configsvr" runtime operation
|
||||||
|
@ -749,8 +823,8 @@ logpath = /var/log/mongodb/mongodb.log
|
||||||
|
|
||||||
logpath = /var/log/fail2ban.log
|
logpath = /var/log/fail2ban.log
|
||||||
banaction = %(banaction_allports)s
|
banaction = %(banaction_allports)s
|
||||||
bantime = 604800 ; 1 week
|
bantime = 1w
|
||||||
findtime = 86400 ; 1 day
|
findtime = 1d
|
||||||
|
|
||||||
|
|
||||||
# Generic filter for PAM. Has to be used with action which bans all
|
# Generic filter for PAM. Has to be used with action which bans all
|
||||||
|
@ -786,11 +860,31 @@ logpath = /var/log/ejabberd/ejabberd.log
|
||||||
[counter-strike]
|
[counter-strike]
|
||||||
|
|
||||||
logpath = /opt/cstrike/logs/L[0-9]*.log
|
logpath = /opt/cstrike/logs/L[0-9]*.log
|
||||||
# Firewall: http://www.cstrike-planet.com/faq/6
|
|
||||||
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
||||||
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
||||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
||||||
%(banaction)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
||||||
|
|
||||||
|
[softethervpn]
|
||||||
|
port = 500,4500
|
||||||
|
protocol = udp
|
||||||
|
logpath = /usr/local/vpnserver/security_log/*/sec.log
|
||||||
|
|
||||||
|
[gitlab]
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/gitlab/gitlab-rails/application.log
|
||||||
|
|
||||||
|
[grafana]
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/grafana/grafana.log
|
||||||
|
|
||||||
|
[bitwarden]
|
||||||
|
port = http,https
|
||||||
|
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
||||||
|
|
||||||
|
[centreon]
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/centreon/login.log
|
||||||
|
|
||||||
# consider low maxretry and a long bantime
|
# consider low maxretry and a long bantime
|
||||||
# nobody except your own Nagios server should ever probe nrpe
|
# nobody except your own Nagios server should ever probe nrpe
|
||||||
|
@ -824,7 +918,9 @@ filter = apache-pass[knocking_url="%(knocking_url)s"]
|
||||||
logpath = %(apache_access_log)s
|
logpath = %(apache_access_log)s
|
||||||
blocktype = RETURN
|
blocktype = RETURN
|
||||||
returntype = DROP
|
returntype = DROP
|
||||||
bantime = 3600
|
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
|
||||||
|
actionstart_on_demand=false, actionrepair_on_unban=true]
|
||||||
|
bantime = 1h
|
||||||
maxretry = 1
|
maxretry = 1
|
||||||
findtime = 1
|
findtime = 1
|
||||||
|
|
||||||
|
@ -832,8 +928,8 @@ findtime = 1
|
||||||
[murmur]
|
[murmur]
|
||||||
# AKA mumble-server
|
# AKA mumble-server
|
||||||
port = 64738
|
port = 64738
|
||||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol=tcp, chain="%(chain)s", actname=%(banaction)s-tcp]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol=udp, chain="%(chain)s", actname=%(banaction)s-udp]
|
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||||
logpath = /var/log/mumble-server/mumble-server.log
|
logpath = /var/log/mumble-server/mumble-server.log
|
||||||
|
|
||||||
|
|
||||||
|
@ -851,5 +947,34 @@ logpath = /var/log/haproxy.log
|
||||||
|
|
||||||
[slapd]
|
[slapd]
|
||||||
port = ldap,ldaps
|
port = ldap,ldaps
|
||||||
filter = slapd
|
|
||||||
logpath = /var/log/slapd.log
|
logpath = /var/log/slapd.log
|
||||||
|
|
||||||
|
[domino-smtp]
|
||||||
|
port = smtp,ssmtp
|
||||||
|
logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
|
||||||
|
|
||||||
|
[phpmyadmin-syslog]
|
||||||
|
port = http,https
|
||||||
|
logpath = %(syslog_authpriv)s
|
||||||
|
backend = %(syslog_backend)s
|
||||||
|
|
||||||
|
|
||||||
|
[zoneminder]
|
||||||
|
# Zoneminder HTTP/HTTPS web interface auth
|
||||||
|
# Logs auth failures to apache2 error log
|
||||||
|
port = http,https
|
||||||
|
logpath = %(apache_error_log)s
|
||||||
|
|
||||||
|
[traefik-auth]
|
||||||
|
# to use 'traefik-auth' filter you have to configure your Traefik instance,
|
||||||
|
# see `filter.d/traefik-auth.conf` for details and service example.
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/traefik/access.log
|
||||||
|
|
||||||
|
[scanlogd]
|
||||||
|
logpath = %(syslog_local0)s
|
||||||
|
banaction = %(banaction_allports)s
|
||||||
|
|
||||||
|
[monitorix]
|
||||||
|
port = 8080
|
||||||
|
logpath = /var/log/monitorix-httpd
|
||||||
|
|
|
@ -3,16 +3,16 @@ ssl_session_cache shared:SSL:50m; # about 200000 sessions
|
||||||
ssl_session_tickets off;
|
ssl_session_tickets off;
|
||||||
|
|
||||||
{% if compatibility == "modern" %}
|
{% if compatibility == "modern" %}
|
||||||
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, modern configuration
|
# generated 2023-06-13, Mozilla Guideline v5.7, nginx 1.22.1, OpenSSL 3.0.9, modern configuration
|
||||||
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=modern&openssl=1.1.1d&guideline=5.6
|
# https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=modern&openssl=3.0.9&guideline=5.7
|
||||||
ssl_protocols TLSv1.3;
|
ssl_protocols TLSv1.3;
|
||||||
ssl_prefer_server_ciphers off;
|
ssl_prefer_server_ciphers off;
|
||||||
{% else %}
|
{% else %}
|
||||||
# Ciphers with intermediate compatibility
|
# Ciphers with intermediate compatibility
|
||||||
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, intermediate configuration
|
# generated 2023-06-13, Mozilla Guideline v5.7, nginx 1.22.1, OpenSSL 3.0.9, intermediate configuration
|
||||||
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6
|
# https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=intermediate&openssl=3.0.9&guideline=5.7
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
|
||||||
ssl_prefer_server_ciphers off;
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
# Pre-defined FFDHE group (RFC 7919)
|
# Pre-defined FFDHE group (RFC 7919)
|
||||||
|
|
|
@ -30,8 +30,8 @@ smtpd_tls_chain_files =
|
||||||
tls_server_sni_maps = hash:/etc/postfix/sni
|
tls_server_sni_maps = hash:/etc/postfix/sni
|
||||||
|
|
||||||
{% if compatibility == "intermediate" %}
|
{% if compatibility == "intermediate" %}
|
||||||
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, intermediate configuration
|
# generated 2023-06-13, Mozilla Guideline v5.7, Postfix 3.7.5, OpenSSL 3.0.9, intermediate configuration
|
||||||
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=intermediate&openssl=1.1.1d&guideline=5.6
|
# https://ssl-config.mozilla.org/#server=postfix&version=3.7.5&config=intermediate&openssl=3.0.9&guideline=5.7
|
||||||
|
|
||||||
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
|
@ -41,10 +41,10 @@ smtpd_tls_mandatory_ciphers = medium
|
||||||
# not actually 1024 bits, this applies to all DHE >= 1024 bits
|
# not actually 1024 bits, this applies to all DHE >= 1024 bits
|
||||||
smtpd_tls_dh1024_param_file = /usr/share/yunohost/ffdhe2048.pem
|
smtpd_tls_dh1024_param_file = /usr/share/yunohost/ffdhe2048.pem
|
||||||
|
|
||||||
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
|
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
||||||
{% else %}
|
{% else %}
|
||||||
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, modern configuration
|
# generated 2023-06-13, Mozilla Guideline v5.7, Postfix 3.7.5, OpenSSL 3.0.9, modern configuration
|
||||||
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=modern&openssl=1.1.1d&guideline=5.6
|
# https://ssl-config.mozilla.org/#server=postfix&version=3.7.5&config=modern&openssl=3.0.9&guideline=5.7
|
||||||
|
|
||||||
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
||||||
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
||||||
|
|
44
debian/changelog
vendored
44
debian/changelog
vendored
|
@ -1,3 +1,47 @@
|
||||||
|
yunohost (12.0.0) unstable; urgency=low
|
||||||
|
|
||||||
|
- Tmp changelog to prepare Bookworm
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 04 May 2023 20:30:19 +0200
|
||||||
|
|
||||||
|
yunohost (11.2.4) stable; urgency=low
|
||||||
|
|
||||||
|
- doc: Improve --help for 'yunohost app install' ([#1702](https://github.com/yunohost/yunohost/pull/1702))
|
||||||
|
- helpers: add new --group option for ynh_add_fpm_config to customize the Group parameter (65d25710)
|
||||||
|
- apps: allow to use jinja {% if foobar %} blocks in their notifications/doc pages (57699289)
|
||||||
|
- apps: BACKUP_CORE_ONLY was not set for pre-upgrade safety backups, resulting in unecessarily large pre-upgrade backups (07daa687)
|
||||||
|
- apps: Use the existing db_name setting for database provising to ease v1->v2 transition with specific db_name ([#1704](https://github.com/yunohost/yunohost/pull/1704))
|
||||||
|
- configpanels/forms: more edge cases with some questions not implementing some methods/attributes (b0fe49ae)
|
||||||
|
- diagnosis: reverse DNS check should be case-insensitive #2235 ([#1705](https://github.com/yunohost/yunohost/pull/1705))
|
||||||
|
- i18n: Translations updated for Galician, Indonesian, Polish, Spanish, Turkish
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Grzegorz Cichocki, José M, Kuba Bazan, ljf (zamentur), massyas, Neko Nekowazarashi, selfhoster1312, Suleyman Harmandar, taco, Tagada)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 31 Aug 2023 17:30:21 +0200
|
||||||
|
|
||||||
|
yunohost (11.2.3) stable; urgency=low
|
||||||
|
|
||||||
|
- apps: fix another case of no attribute 'value' due to config panels/questions refactoring (4fda8ed49)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 22 Jul 2023 16:48:22 +0200
|
||||||
|
|
||||||
|
yunohost (11.2.2) stable; urgency=low
|
||||||
|
|
||||||
|
- domains: Gandi's `api_protocol` field should be a `select` type ([#1693](https://github.com/yunohost/yunohost/pull/1693))
|
||||||
|
- configpanel: fix .value call for readonly-type options (e1ceb084)
|
||||||
|
- i18n: Translations updated for French, Galician
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (axolotle, José M, ppr, tituspijean)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 19 Jul 2023 02:35:28 +0200
|
||||||
|
|
||||||
|
yunohost (11.2.1) stable; urgency=low
|
||||||
|
|
||||||
|
- doc: fix resource doc generation .. not sure why this line that removed legit indent was there (ced222ea)
|
||||||
|
- apps: hotfix for funky issue, apps getting named 'undefined' (781f924e)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 17 Jul 2023 21:13:54 +0200
|
||||||
|
|
||||||
yunohost (11.2) stable; urgency=low
|
yunohost (11.2) stable; urgency=low
|
||||||
|
|
||||||
- dyndns: add support for recovery passwords ([#1475](https://github.com/YunoHost/yunohost/pull/1475))
|
- dyndns: add support for recovery passwords ([#1475](https://github.com/YunoHost/yunohost/pull/1475))
|
||||||
|
|
25
debian/control
vendored
25
debian/control
vendored
|
@ -2,7 +2,7 @@ Source: yunohost
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: YunoHost Contributors <contrib@yunohost.org>
|
Maintainer: YunoHost Contributors <contrib@yunohost.org>
|
||||||
Build-Depends: debhelper (>=9), debhelper-compat (= 13), dh-python, python3-all (>= 3.7), python3-yaml, python3-jinja2
|
Build-Depends: debhelper (>=9), debhelper-compat (= 13), dh-python, python3-all (>= 3.11), python3-yaml, python3-jinja2
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
Homepage: https://yunohost.org/
|
Homepage: https://yunohost.org/
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@ Depends: ${python3:Depends}, ${misc:Depends}
|
||||||
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
||||||
, python3-miniupnpc, python3-dbus, python3-jinja2
|
, python3-miniupnpc, python3-dbus, python3-jinja2
|
||||||
, python3-toml, python3-packaging, python3-publicsuffix2
|
, python3-toml, python3-packaging, python3-publicsuffix2
|
||||||
, python3-ldap, python3-zeroconf (>= 0.36), python3-lexicon,
|
, python3-ldap, python3-zeroconf (>= 0.47), python3-lexicon,
|
||||||
, python3-cryptography, python3-jwt
|
, python3-cryptography, python3-jwt
|
||||||
, python-is-python3
|
, python-is-python3
|
||||||
, nginx, nginx-extras (>=1.18)
|
, nginx, nginx-extras (>=1.22)
|
||||||
, apt, apt-transport-https, apt-utils, dirmngr
|
, apt, apt-transport-https, apt-utils, dirmngr
|
||||||
, openssh-server, iptables, fail2ban, bind9-dnsutils
|
, openssh-server, iptables, fail2ban, bind9-dnsutils
|
||||||
, openssl, ca-certificates, netcat-openbsd, iproute2
|
, openssl, ca-certificates, netcat-openbsd, iproute2
|
||||||
|
@ -33,23 +33,18 @@ Depends: ${python3:Depends}, ${misc:Depends}
|
||||||
Recommends: yunohost-admin
|
Recommends: yunohost-admin
|
||||||
, ntp, inetutils-ping | iputils-ping
|
, ntp, inetutils-ping | iputils-ping
|
||||||
, bash-completion, rsyslog
|
, bash-completion, rsyslog
|
||||||
, php7.4-common, php7.4-fpm, php7.4-ldap, php7.4-intl
|
|
||||||
, mariadb-server, php7.4-mysql
|
|
||||||
, php7.4-gd, php7.4-curl, php-php-gettext
|
|
||||||
, python3-pip
|
|
||||||
, unattended-upgrades
|
, unattended-upgrades
|
||||||
, libdbd-ldap-perl, libnet-dns-perl
|
, libdbd-ldap-perl, libnet-dns-perl
|
||||||
, metronome (>=3.14.0)
|
|
||||||
Conflicts: iptables-persistent
|
Conflicts: iptables-persistent
|
||||||
, apache2
|
, apache2
|
||||||
, bind9
|
, bind9
|
||||||
, nginx-extras (>= 1.19)
|
, nginx-extras (>= 1.23)
|
||||||
, openssl (>= 1.1.1o-0)
|
, openssl (>= 3.1)
|
||||||
, slapd (>= 2.4.58)
|
, slapd (>= 2.6)
|
||||||
, dovecot-core (>= 1:2.3.14)
|
, dovecot-core (>= 1:2.4)
|
||||||
, redis-server (>= 5:6.1)
|
, redis-server (>= 5:7.1)
|
||||||
, fail2ban (>= 0.11.3)
|
, fail2ban (>= 1.1)
|
||||||
, iptables (>= 1.8.8)
|
, iptables (>= 1.8.10)
|
||||||
Description: manageable and configured self-hosting server
|
Description: manageable and configured self-hosting server
|
||||||
YunoHost aims to make self-hosting accessible to everyone. It configures
|
YunoHost aims to make self-hosting accessible to everyone. It configures
|
||||||
an email, Web and IM server alongside a LDAP base. It also provides
|
an email, Web and IM server alongside a LDAP base. It also provides
|
||||||
|
|
|
@ -62,8 +62,6 @@ for c in ResourceClasses:
|
||||||
|
|
||||||
|
|
||||||
for resource_id, doc in sorted(ResourceDocString.items()):
|
for resource_id, doc in sorted(ResourceDocString.items()):
|
||||||
doc = doc.replace("\n ", "\n")
|
|
||||||
|
|
||||||
print("----------------")
|
print("----------------")
|
||||||
print("")
|
print("")
|
||||||
print(f"## {resource_id.replace('_', ' ').title()}")
|
print(f"## {resource_id.replace('_', ' ').title()}")
|
||||||
|
|
|
@ -210,6 +210,9 @@ ynh_mysql_setup_db() {
|
||||||
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd
|
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd
|
||||||
db_pwd="${db_pwd:-$new_db_pwd}"
|
db_pwd="${db_pwd:-$new_db_pwd}"
|
||||||
|
|
||||||
|
# Dirty patch for super-legacy apps
|
||||||
|
dpkg --list | grep -q "^ii mariadb-server" || { ynh_print_warn "Packager: you called ynh_mysql_setup_db without declaring a dependency to mariadb-server. Please add it to your apt dependencies !"; ynh_apt install mariadb-server; }
|
||||||
|
|
||||||
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd"
|
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd"
|
||||||
ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd
|
ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd
|
||||||
}
|
}
|
||||||
|
|
170
helpers/php
170
helpers/php
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
readonly YNH_DEFAULT_PHP_VERSION=7.4
|
readonly YNH_DEFAULT_PHP_VERSION=8.2
|
||||||
# Declare the actual PHP version to use.
|
# Declare the actual PHP version to use.
|
||||||
# A packager willing to use another version of PHP can override the variable into its _common.sh.
|
# A packager willing to use another version of PHP can override the variable into its _common.sh.
|
||||||
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
|
@ -70,16 +70,15 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
ynh_add_fpm_config() {
|
ynh_add_fpm_config() {
|
||||||
local _globalphpversion=${phpversion-:}
|
local _globalphpversion=${phpversion-:}
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vufpd
|
local legacy_args=vufg
|
||||||
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
|
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [g]=group=)
|
||||||
|
local group
|
||||||
local phpversion
|
local phpversion
|
||||||
local usage
|
local usage
|
||||||
local footprint
|
local footprint
|
||||||
local package
|
|
||||||
local dedicated_service
|
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
package=${package:-}
|
group=${group:-}
|
||||||
|
|
||||||
# The default behaviour is to use the template.
|
# The default behaviour is to use the template.
|
||||||
local autogenconf=false
|
local autogenconf=false
|
||||||
|
@ -105,8 +104,6 @@ ynh_add_fpm_config() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
# Do not use a dedicated service by default
|
|
||||||
dedicated_service=${dedicated_service:-0}
|
|
||||||
|
|
||||||
# Set the default PHP-FPM version by default
|
# Set the default PHP-FPM version by default
|
||||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||||
|
@ -130,45 +127,16 @@ ynh_add_fpm_config() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Legacy args (packager should just list their php dependency as regular apt dependencies...
|
local fpm_service="php${phpversion}-fpm"
|
||||||
if [ -n "$package" ]; then
|
local fpm_config_dir="/etc/php/$phpversion/fpm"
|
||||||
# Install the additionnal packages from the default repository
|
|
||||||
ynh_print_warn --message "Argument --package of ynh_add_fpm_config is deprecated and to be removed in the future"
|
|
||||||
ynh_install_app_dependencies "$package"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
|
||||||
ynh_print_warn --message "Argument --dedicated_service of ynh_add_fpm_config is deprecated and to be removed in the future"
|
|
||||||
local fpm_service="${app}-phpfpm"
|
|
||||||
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
|
|
||||||
else
|
|
||||||
local fpm_service="php${phpversion}-fpm"
|
|
||||||
local fpm_config_dir="/etc/php/$phpversion/fpm"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the directory for FPM pools
|
# Create the directory for FPM pools
|
||||||
mkdir --parents "$fpm_config_dir/pool.d"
|
mkdir --parents "$fpm_config_dir/pool.d"
|
||||||
|
|
||||||
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
|
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
|
||||||
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
|
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
|
||||||
ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service"
|
|
||||||
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
|
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
|
||||||
|
|
||||||
# Migrate from mutual PHP service to dedicated one.
|
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
|
||||||
local old_fpm_config_dir="/etc/php/$phpversion/fpm"
|
|
||||||
# If a config file exist in the common pool, move it.
|
|
||||||
if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ]; then
|
|
||||||
ynh_print_info --message="Migrate to a dedicated php-fpm service for $app."
|
|
||||||
# Create a backup of the old file before migration
|
|
||||||
ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf"
|
|
||||||
# Remove the old PHP config file
|
|
||||||
ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf"
|
|
||||||
# Reload PHP to release the socket and allow the dedicated service to use it
|
|
||||||
ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $autogenconf == "false" ]; then
|
if [ $autogenconf == "false" ]; then
|
||||||
# Usage 1, use the template in conf/php-fpm.conf
|
# Usage 1, use the template in conf/php-fpm.conf
|
||||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||||
|
@ -180,12 +148,13 @@ ynh_add_fpm_config() {
|
||||||
# Define the values to use for the configuration of PHP.
|
# Define the values to use for the configuration of PHP.
|
||||||
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
|
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
|
||||||
|
|
||||||
|
local phpfpm_group=$([[ -n "$group" ]] && echo "$group" || echo "$app")
|
||||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||||
echo "
|
echo "
|
||||||
[__APP__]
|
[__APP__]
|
||||||
|
|
||||||
user = __APP__
|
user = __APP__
|
||||||
group = __APP__
|
group = __PHPFPM_GROUP__
|
||||||
|
|
||||||
chdir = __INSTALL_DIR__
|
chdir = __INSTALL_DIR__
|
||||||
|
|
||||||
|
@ -221,56 +190,13 @@ pm.process_idle_timeout = 10s
|
||||||
local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
|
local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
|
||||||
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
|
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
|
||||||
|
|
||||||
if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then
|
# Validate that the new php conf doesn't break php-fpm entirely
|
||||||
ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead."
|
if ! php-fpm${phpversion} --test 2>/dev/null; then
|
||||||
ynh_add_config --template="php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini"
|
php-fpm${phpversion} --test || true
|
||||||
fi
|
ynh_secure_remove --file="$finalphpconf"
|
||||||
|
ynh_die --message="The new configuration broke php-fpm?"
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
|
||||||
# Create a dedicated php-fpm.conf for the service
|
|
||||||
local globalphpconf=$fpm_config_dir/php-fpm-$app.conf
|
|
||||||
|
|
||||||
echo "[global]
|
|
||||||
pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid
|
|
||||||
error_log = /var/log/php/fpm-php.__APP__.log
|
|
||||||
syslog.ident = php-fpm-__APP__
|
|
||||||
include = __FINALPHPCONF__
|
|
||||||
" >$YNH_APP_BASEDIR/conf/php-fpm-$app.conf
|
|
||||||
|
|
||||||
ynh_add_config --template="php-fpm-$app.conf" --destination="$globalphpconf"
|
|
||||||
|
|
||||||
# Create a config for a dedicated PHP-FPM service for the app
|
|
||||||
echo "[Unit]
|
|
||||||
Description=PHP __PHPVERSION__ FastCGI Process Manager for __APP__
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=notify
|
|
||||||
PIDFile=/run/php/php__PHPVERSION__-fpm-__APP__.pid
|
|
||||||
ExecStart=/usr/sbin/php-fpm__PHPVERSION__ --nodaemonize --fpm-config __GLOBALPHPCONF__
|
|
||||||
ExecReload=/bin/kill -USR2 \$MAINPID
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
" >$YNH_APP_BASEDIR/conf/$fpm_service
|
|
||||||
|
|
||||||
# Create this dedicated PHP-FPM service
|
|
||||||
ynh_add_systemd_config --service=$fpm_service --template=$fpm_service
|
|
||||||
# Integrate the service in YunoHost admin panel
|
|
||||||
yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --description "Php-fpm dedicated to $app"
|
|
||||||
# Configure log rotate
|
|
||||||
ynh_use_logrotate --logfile=/var/log/php
|
|
||||||
# Restart the service, as this service is either stopped or only for this app
|
|
||||||
ynh_systemd_action --service_name=$fpm_service --action=restart
|
|
||||||
else
|
|
||||||
# Validate that the new php conf doesn't break php-fpm entirely
|
|
||||||
if ! php-fpm${phpversion} --test 2>/dev/null; then
|
|
||||||
php-fpm${phpversion} --test || true
|
|
||||||
ynh_secure_remove --file="$finalphpconf"
|
|
||||||
ynh_die --message="The new configuration broke php-fpm?"
|
|
||||||
fi
|
|
||||||
ynh_systemd_action --service_name=$fpm_service --action=reload
|
|
||||||
fi
|
fi
|
||||||
|
ynh_systemd_action --service_name=$fpm_service --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the dedicated PHP-FPM config
|
# Remove the dedicated PHP-FPM config
|
||||||
|
@ -281,8 +207,6 @@ WantedBy=multi-user.target
|
||||||
ynh_remove_fpm_config() {
|
ynh_remove_fpm_config() {
|
||||||
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
||||||
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
|
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
|
||||||
local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service)
|
|
||||||
dedicated_service=${dedicated_service:-0}
|
|
||||||
# Get the version of PHP used by this app
|
# Get the version of PHP used by this app
|
||||||
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
||||||
|
|
||||||
|
@ -296,69 +220,7 @@ ynh_remove_fpm_config() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
|
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
|
||||||
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]; then
|
ynh_systemd_action --service_name=$fpm_service --action=reload
|
||||||
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
|
||||||
# Remove the dedicated service PHP-FPM service for the app
|
|
||||||
ynh_remove_systemd_config --service=$fpm_service
|
|
||||||
# Remove the global PHP-FPM conf
|
|
||||||
ynh_secure_remove --file="$fpm_config_dir/php-fpm-$app.conf"
|
|
||||||
# Remove the service from the list of services known by YunoHost
|
|
||||||
yunohost service remove $fpm_service
|
|
||||||
elif ynh_package_is_installed --package="php${phpversion}-fpm"; then
|
|
||||||
ynh_systemd_action --service_name=$fpm_service --action=reload
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If the PHP version used is not the default version for YunoHost
|
|
||||||
# The second part with YNH_APP_PURGE is an ugly hack to guess that we're inside the remove script
|
|
||||||
# (we don't actually care about its value, we just check its not empty hence it exists)
|
|
||||||
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] && [ -n "${YNH_APP_PURGE:-}" ] && dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
|
||||||
# Remove app dependencies ... but ideally should happen via an explicit call from packager
|
|
||||||
ynh_remove_app_dependencies
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install another version of PHP.
|
|
||||||
#
|
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# Legacy, to be remove on bullseye
|
|
||||||
#
|
|
||||||
# usage: ynh_install_php --phpversion=phpversion [--package=packages]
|
|
||||||
# | arg: -v, --phpversion= - Version of PHP to install.
|
|
||||||
# | arg: -p, --package= - Additionnal PHP packages to install
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
|
||||||
ynh_install_php() {
|
|
||||||
# Declare an array to define the options of this helper.
|
|
||||||
local legacy_args=vp
|
|
||||||
local -A args_array=([v]=phpversion= [p]=package=)
|
|
||||||
local phpversion
|
|
||||||
local package
|
|
||||||
# Manage arguments with getopts
|
|
||||||
ynh_handle_getopts_args "$@"
|
|
||||||
package=${package:-}
|
|
||||||
|
|
||||||
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]; then
|
|
||||||
ynh_die --message="Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ynh_install_app_dependencies "$package"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Remove the specific version of PHP used by the app.
|
|
||||||
#
|
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# Legacy, to be remove on bullseye
|
|
||||||
#
|
|
||||||
# usage: ynh_remove_php
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
|
||||||
ynh_remove_php () {
|
|
||||||
ynh_remove_app_dependencies
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Define the values to configure PHP-FPM
|
# Define the values to configure PHP-FPM
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
||||||
PSQL_VERSION=13
|
PSQL_VERSION=15
|
||||||
|
|
||||||
# Open a connection as a user
|
# Open a connection as a user
|
||||||
#
|
#
|
||||||
|
|
|
@ -18,11 +18,7 @@ ynh_app_setting_get() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
app="${app:-$_globalapp}"
|
app="${app:-$_globalapp}"
|
||||||
|
|
||||||
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then
|
ynh_app_setting "get" "$app" "$key"
|
||||||
yunohost app setting $app $key
|
|
||||||
else
|
|
||||||
ynh_app_setting "get" "$app" "$key"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set an application setting
|
# Set an application setting
|
||||||
|
@ -45,11 +41,7 @@ ynh_app_setting_set() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
app="${app:-$_globalapp}"
|
app="${app:-$_globalapp}"
|
||||||
|
|
||||||
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then
|
ynh_app_setting "set" "$app" "$key" "$value"
|
||||||
yunohost app setting $app $key -v $value
|
|
||||||
else
|
|
||||||
ynh_app_setting "set" "$app" "$key" "$value"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Delete an application setting
|
# Delete an application setting
|
||||||
|
@ -70,11 +62,7 @@ ynh_app_setting_delete() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
app="${app:-$_globalapp}"
|
app="${app:-$_globalapp}"
|
||||||
|
|
||||||
if [[ "$key" =~ (unprotected|skipped|protected)_ ]]; then
|
ynh_app_setting "delete" "$app" "$key"
|
||||||
yunohost app setting $app $key -d
|
|
||||||
else
|
|
||||||
ynh_app_setting "delete" "$app" "$key"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Small "hard-coded" interface to avoid calling "yunohost app" directly each
|
# Small "hard-coded" interface to avoid calling "yunohost app" directly each
|
||||||
|
|
|
@ -75,7 +75,7 @@ fi
|
||||||
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]
|
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]
|
||||||
# | arg: -d, --dest_dir= - Directory where to setup sources
|
# | arg: -d, --dest_dir= - Directory where to setup sources
|
||||||
# | arg: -s, --source_id= - Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise
|
# | arg: -s, --source_id= - Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise
|
||||||
# | arg: -k, --keep= - Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs/'
|
# | arg: -k, --keep= - Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs' (no trailing `/` for folders)
|
||||||
# | arg: -r, --full_replace= - Remove previous sources before installing new sources
|
# | arg: -r, --full_replace= - Remove previous sources before installing new sources
|
||||||
#
|
#
|
||||||
# #### New 'sources' resources
|
# #### New 'sources' resources
|
||||||
|
@ -244,9 +244,11 @@ ynh_setup_source() {
|
||||||
|
|
||||||
if [ "$src_format" = "docker" ]; then
|
if [ "$src_format" = "docker" ]; then
|
||||||
src_platform="${src_platform:-"linux/$YNH_ARCH"}"
|
src_platform="${src_platform:-"linux/$YNH_ARCH"}"
|
||||||
elif test -e "$local_src"; then
|
|
||||||
cp $local_src $src_filename
|
|
||||||
else
|
else
|
||||||
|
if test -e "$local_src"; then
|
||||||
|
cp $local_src $src_filename
|
||||||
|
fi
|
||||||
|
|
||||||
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
||||||
|
|
||||||
# If the file was prefetched but somehow doesn't match the sum, rm and redownload it
|
# If the file was prefetched but somehow doesn't match the sum, rm and redownload it
|
||||||
|
|
|
@ -9,5 +9,5 @@ source /usr/share/yunohost/helpers
|
||||||
# Backup destination
|
# Backup destination
|
||||||
backup_dir="${1}/data/xmpp"
|
backup_dir="${1}/data/xmpp"
|
||||||
|
|
||||||
ynh_backup /var/lib/metronome "${backup_dir}/var_lib_metronome"
|
[[ ! -d /var/lib/metronome ]] || ynh_backup /var/lib/metronome "${backup_dir}/var_lib_metronome" --not_mandatory
|
||||||
ynh_backup /var/xmpp-upload/ "${backup_dir}/var_xmpp-upload"
|
[[ ! -d /var/xmpp-upload ]] || ynh_backup /var/xmpp-upload/ "${backup_dir}/var_xmpp-upload" --not_mandatory
|
||||||
|
|
|
@ -11,7 +11,7 @@ do_pre_regen() {
|
||||||
|
|
||||||
# Add sury
|
# Add sury
|
||||||
mkdir -p ${pending_dir}/etc/apt/sources.list.d/
|
mkdir -p ${pending_dir}/etc/apt/sources.list.d/
|
||||||
echo "deb https://packages.sury.org/php/ $(lsb_release --codename --short) main" > "${pending_dir}/etc/apt/sources.list.d/extra_php_version.list"
|
echo "deb [signed-by=/etc/apt/trusted.gpg.d/extra_php_version.gpg] https://packages.sury.org/php/ $(lsb_release --codename --short) main" > "${pending_dir}/etc/apt/sources.list.d/extra_php_version.list"
|
||||||
|
|
||||||
# Ban some packages from sury
|
# Ban some packages from sury
|
||||||
echo "
|
echo "
|
||||||
|
@ -27,6 +27,20 @@ Pin: origin \"packages.sury.org\"
|
||||||
Pin-Priority: -1" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
Pin-Priority: -1" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Add yarn
|
||||||
|
echo "deb [signed-by=/etc/apt/trusted.gpg.d/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > "${pending_dir}/etc/apt/sources.list.d/yarn.list"
|
||||||
|
|
||||||
|
# Ban everything from Yarn except Yarn
|
||||||
|
echo "
|
||||||
|
Package: *
|
||||||
|
Pin: origin \"dl.yarnpkg.com\"
|
||||||
|
Pin-Priority: -1
|
||||||
|
|
||||||
|
Package: yarn
|
||||||
|
Pin: origin \"dl.yarnpkg.com\"
|
||||||
|
Pin-Priority: 500" >>"${pending_dir}/etc/apt/preferences.d/yarn"
|
||||||
|
|
||||||
|
# Ban apache2, bind9
|
||||||
echo "
|
echo "
|
||||||
|
|
||||||
# PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
|
# PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
|
||||||
|
@ -69,6 +83,12 @@ do_post_regen() {
|
||||||
wget --timeout 900 --quiet "https://packages.sury.org/php/apt.gpg" --output-document=- | gpg --dearmor >"/etc/apt/trusted.gpg.d/extra_php_version.gpg"
|
wget --timeout 900 --quiet "https://packages.sury.org/php/apt.gpg" --output-document=- | gpg --dearmor >"/etc/apt/trusted.gpg.d/extra_php_version.gpg"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Similar to Sury
|
||||||
|
if [[ ! -s /etc/apt/trusted.gpg.d/yarn.gpg ]]
|
||||||
|
then
|
||||||
|
wget --timeout 900 --quiet "https://dl.yarnpkg.com/debian/pubkey.gpg" --output-document=- | gpg --dearmor >"/etc/apt/trusted.gpg.d/yarn.gpg"
|
||||||
|
fi
|
||||||
|
|
||||||
# Make sure php7.4 is the default version when using php in cli
|
# Make sure php7.4 is the default version when using php in cli
|
||||||
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
||||||
then
|
then
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
backup_dir="$1/data/xmpp"
|
backup_dir="$1/data/xmpp"
|
||||||
|
|
||||||
cp -a $backup_dir/var_lib_metronome/. /var/lib/metronome
|
if [[ -e $backup_dir/var_lib_metronome/ ]]
|
||||||
cp -a $backup_dir/var_xmpp-upload/. /var/xmpp-upload
|
then
|
||||||
|
cp -a $backup_dir/var_lib_metronome/. /var/lib/metronome
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e $backup_dir/var_xmpp-upload ]]
|
||||||
|
then
|
||||||
|
cp -a $backup_dir/var_xmpp-upload/. /var/xmpp-upload
|
||||||
|
fi
|
||||||
|
|
|
@ -588,7 +588,20 @@
|
||||||
"migration_0024_rebuild_python_venv_disclaimer_rebuild": "Rebuilding the virtualenv will be attempted for the following apps (NB: the operation may take some time!): {rebuild_apps}",
|
"migration_0024_rebuild_python_venv_disclaimer_rebuild": "Rebuilding the virtualenv will be attempted for the following apps (NB: the operation may take some time!): {rebuild_apps}",
|
||||||
"migration_0024_rebuild_python_venv_failed": "Failed to rebuild the Python virtualenv for {app}. The app may not work as long as this is not resolved. You should fix the situation by forcing the upgrade of this app using `yunohost app upgrade --force {app}`.",
|
"migration_0024_rebuild_python_venv_failed": "Failed to rebuild the Python virtualenv for {app}. The app may not work as long as this is not resolved. You should fix the situation by forcing the upgrade of this app using `yunohost app upgrade --force {app}`.",
|
||||||
"migration_0024_rebuild_python_venv_in_progress": "Now attempting to rebuild the Python virtualenv for `{app}`",
|
"migration_0024_rebuild_python_venv_in_progress": "Now attempting to rebuild the Python virtualenv for `{app}`",
|
||||||
"migration_description_0021_migrate_to_bullseye": "Upgrade the system to Debian Bullseye and YunoHost 11.x",
|
"migration_0027_cleaning_up": "Cleaning up cache and packages not useful anymore...",
|
||||||
|
"migration_0027_hgjghjghjgeneral_warning": "Please note that this migration is a delicate operation. The YunoHost team did its best to review and test it, but the migration might still break parts of the system or its apps.\n\nTherefore, it is recommended to:\n - Perform a backup of any critical data or app. More info on https://yunohost.org/backup;\n - Be patient after launching the migration: Depending on your Internet connection and hardware, it might take up to a few hours for everything to upgrade.",
|
||||||
|
"migration_0027_main_upgrade": "Starting main upgrade...",
|
||||||
|
"migration_0027_modified_files": "Please note that the following files were found to be manually modified and might be overwritten following the upgrade: {manually_modified_files}",
|
||||||
|
"migration_0027_not_buster2": "The current Debian distribution is not Bullseye! If you already ran the Bullseye->Bookworm migration, then this error is symptomatic of the fact that the migration procedure was not 100% succesful (otherwise YunoHost would have flagged it as completed). It is recommended to investigate what happened with the support team, who will need the **full** log of the `migration, which can be found in Tools > Logs in the webadmin.",
|
||||||
|
"migration_0027_not_enough_free_space": "Free space is pretty low in /var/! You should have at least 1GB free to run this migration.",
|
||||||
|
"migration_0027_patch_yunohost_conflicts": "Applying patch to workaround conflict issue...",
|
||||||
|
"migration_0027_patching_sources_list": "Patching the sources.lists...",
|
||||||
|
"migration_0027_problematic_apps_warning": "Please note that the following possibly problematic installed apps were detected. It looks like those were not installed from the YunoHost app catalog, or are not flagged as 'working'. Consequently, it cannot be guaranteed that they will still work after the upgrade: {problematic_apps}",
|
||||||
|
"migration_0027_start": "Starting migration to Bookworm",
|
||||||
|
"migration_0027_still_on_buster_after_main_upgrade": "Something went wrong during the main upgrade, the system appears to still be on Debian Bullseye",
|
||||||
|
"migration_0027_system_not_fully_up_to_date": "Your system is not fully up-to-date. Please perform a regular upgrade before running the migration to Bookworm.",
|
||||||
|
"migration_0027_yunohost_upgrade": "Starting YunoHost core upgrade...",
|
||||||
|
"migration_description_0021_migrate_to_bullseye": "Upgrade the system to Debian Bookworm and YunoHost 12",
|
||||||
"migration_description_0022_php73_to_php74_pools": "Migrate php7.3-fpm 'pool' conf files to php7.4",
|
"migration_description_0022_php73_to_php74_pools": "Migrate php7.3-fpm 'pool' conf files to php7.4",
|
||||||
"migration_description_0023_postgresql_11_to_13": "Migrate databases from PostgreSQL 11 to 13",
|
"migration_description_0023_postgresql_11_to_13": "Migrate databases from PostgreSQL 11 to 13",
|
||||||
"migration_description_0024_rebuild_python_venv": "Repair Python app after bullseye migration",
|
"migration_description_0024_rebuild_python_venv": "Repair Python app after bullseye migration",
|
||||||
|
|
|
@ -522,8 +522,8 @@
|
||||||
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Algunos proveedores de internet no le permitirán desbloquear el puerto 25 porque no les importa la Neutralidad de la Red.<br> - Algunos proporcionan una alternativa usando <a href='https://yunohost.org/#/email_configure_relay'>un relay como servidor de correo</a> lo que implica que el relay podrá espiar tu tráfico de correo.<br>- Una alternativa buena para la privacidad es utilizar una VPN *con una IP pública dedicada* para evitar estas limitaciones. Mira en <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- Otra alternativa es cambiar de proveedor de internet a <a href='https://yunohost.org/#/isp'>uno más amable con la Neutralidad de la Red</a>",
|
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Algunos proveedores de internet no le permitirán desbloquear el puerto 25 porque no les importa la Neutralidad de la Red.<br> - Algunos proporcionan una alternativa usando <a href='https://yunohost.org/#/email_configure_relay'>un relay como servidor de correo</a> lo que implica que el relay podrá espiar tu tráfico de correo.<br>- Una alternativa buena para la privacidad es utilizar una VPN *con una IP pública dedicada* para evitar estas limitaciones. Mira en <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- Otra alternativa es cambiar de proveedor de internet a <a href='https://yunohost.org/#/isp'>uno más amable con la Neutralidad de la Red</a>",
|
||||||
"diagnosis_backports_in_sources_list": "Parece que apt (el gestor de paquetes) está configurado para usar el repositorio backports. A menos que realmente sepas lo que estás haciendo, desaconsejamos absolutamente instalar paquetes desde backports, ya que pueden provocar comportamientos intestables o conflictos en el sistema.",
|
"diagnosis_backports_in_sources_list": "Parece que apt (el gestor de paquetes) está configurado para usar el repositorio backports. A menos que realmente sepas lo que estás haciendo, desaconsejamos absolutamente instalar paquetes desde backports, ya que pueden provocar comportamientos intestables o conflictos en el sistema.",
|
||||||
"diagnosis_basesystem_hardware_model": "El modelo de servidor es {model}",
|
"diagnosis_basesystem_hardware_model": "El modelo de servidor es {model}",
|
||||||
"additional_urls_already_removed": "La URL adicional '{url}' ya se ha eliminado para el permiso «{permission}»",
|
"additional_urls_already_removed": "URL adicional '{url}' ya eliminada en la URL adicional para permiso «{permission}»",
|
||||||
"additional_urls_already_added": "La URL adicional '{url}' ya se ha añadido para el permiso «{permission}»",
|
"additional_urls_already_added": "URL adicional '{url}' ya añadida en la URL adicional para permiso «{permission}»",
|
||||||
"config_apply_failed": "Falló la aplicación de la nueva configuración: {error}",
|
"config_apply_failed": "Falló la aplicación de la nueva configuración: {error}",
|
||||||
"app_restore_script_failed": "Ha ocurrido un error dentro del script de restauración de aplicaciones",
|
"app_restore_script_failed": "Ha ocurrido un error dentro del script de restauración de aplicaciones",
|
||||||
"app_config_unable_to_apply": "No se pudieron aplicar los valores del panel configuración.",
|
"app_config_unable_to_apply": "No se pudieron aplicar los valores del panel configuración.",
|
||||||
|
@ -747,5 +747,10 @@
|
||||||
"global_settings_setting_smtp_relay_host": "Host de retransmisión SMTP",
|
"global_settings_setting_smtp_relay_host": "Host de retransmisión SMTP",
|
||||||
"migration_0024_rebuild_python_venv_disclaimer_rebuild": "Se intentará reconstruir el virtualenv para las siguientes apps (NB: ¡la operación puede llevar algún tiempo!): {rebuild_apps}",
|
"migration_0024_rebuild_python_venv_disclaimer_rebuild": "Se intentará reconstruir el virtualenv para las siguientes apps (NB: ¡la operación puede llevar algún tiempo!): {rebuild_apps}",
|
||||||
"migration_description_0025_global_settings_to_configpanel": "Migración de la nomenclatura de ajustes globales heredada a la nomenclatura nueva y moderna",
|
"migration_description_0025_global_settings_to_configpanel": "Migración de la nomenclatura de ajustes globales heredada a la nomenclatura nueva y moderna",
|
||||||
"registrar_infos": "Información sobre el registrador"
|
"registrar_infos": "Información sobre el registrador",
|
||||||
|
"app_failed_to_download_asset": "Error al descargar el recurso '{source_id}' ({url}) para {app}: {out}",
|
||||||
|
"app_corrupt_source": "YunoHost ha podido descargar el recurso '{source_id}' ({url}) para {app}, pero no coincide con la suma de comprobación esperada. Esto puede significar que ocurrió un fallo de red en tu servidor, o que el recurso ha sido modificado por el responsable de la aplicación (¿o un actor malicioso?) y los responsables de empaquetar esta aplicación para YunoHost necesitan investigar y actualizar el manifesto de la aplicación para reflejar estos cambios. \n Suma de control sha256 esperada: {expected_sha256}\n Suma de control sha256 descargada: {computed_sha256}\n Tamaño del archivo descargado: {size}",
|
||||||
|
"app_change_url_failed": "No es possible cambiar la URL para {app}: {error}",
|
||||||
|
"app_change_url_require_full_domain": "{app} no se puede mover a esta nueva URL porque requiere un dominio completo (es decir, con una ruta = /)",
|
||||||
|
"app_change_url_script_failed": "Se ha producido un error en el script de modificación de la url"
|
||||||
}
|
}
|
|
@ -527,7 +527,7 @@
|
||||||
"pattern_email_forward": "L'adresse électronique doit être valide, le symbole '+' étant accepté (par exemple : johndoe+yunohost@exemple.com)",
|
"pattern_email_forward": "L'adresse électronique doit être valide, le symbole '+' étant accepté (par exemple : johndoe+yunohost@exemple.com)",
|
||||||
"global_settings_setting_smtp_relay_password": "Mot de passe du relais SMTP",
|
"global_settings_setting_smtp_relay_password": "Mot de passe du relais SMTP",
|
||||||
"diagnosis_package_installed_from_sury": "Des paquets du système devraient être rétrogradé de version",
|
"diagnosis_package_installed_from_sury": "Des paquets du système devraient être rétrogradé de version",
|
||||||
"additional_urls_already_added": "URL supplémentaire '{url}' déjà ajoutée pour la permission '{permission}'",
|
"additional_urls_already_added": "L'URL supplémentaire '{url}' a déjà été ajoutée pour la permission '{permission}'",
|
||||||
"unknown_main_domain_path": "Domaine ou chemin inconnu pour '{app}'. Vous devez spécifier un domaine et un chemin pour pouvoir spécifier une URL pour l'autorisation.",
|
"unknown_main_domain_path": "Domaine ou chemin inconnu pour '{app}'. Vous devez spécifier un domaine et un chemin pour pouvoir spécifier une URL pour l'autorisation.",
|
||||||
"show_tile_cant_be_enabled_for_regex": "Vous ne pouvez pas activer 'show_tile' pour le moment, cela car l'URL de l'autorisation '{permission}' est une expression régulière",
|
"show_tile_cant_be_enabled_for_regex": "Vous ne pouvez pas activer 'show_tile' pour le moment, cela car l'URL de l'autorisation '{permission}' est une expression régulière",
|
||||||
"show_tile_cant_be_enabled_for_url_not_defined": "Vous ne pouvez pas activer 'show_tile' pour le moment, car vous devez d'abord définir une URL pour l'autorisation '{permission}'",
|
"show_tile_cant_be_enabled_for_url_not_defined": "Vous ne pouvez pas activer 'show_tile' pour le moment, car vous devez d'abord définir une URL pour l'autorisation '{permission}'",
|
||||||
|
@ -536,7 +536,7 @@
|
||||||
"permission_protected": "L'autorisation {permission} est protégée. Vous ne pouvez pas ajouter ou supprimer le groupe visiteurs à/de cette autorisation.",
|
"permission_protected": "L'autorisation {permission} est protégée. Vous ne pouvez pas ajouter ou supprimer le groupe visiteurs à/de cette autorisation.",
|
||||||
"invalid_regex": "Regex non valide : '{regex}'",
|
"invalid_regex": "Regex non valide : '{regex}'",
|
||||||
"app_label_deprecated": "Cette commande est obsolète ! Veuillez utiliser la nouvelle commande 'yunohost user permission update' pour gérer l'étiquette de l'application.",
|
"app_label_deprecated": "Cette commande est obsolète ! Veuillez utiliser la nouvelle commande 'yunohost user permission update' pour gérer l'étiquette de l'application.",
|
||||||
"additional_urls_already_removed": "URL supplémentaire '{url}' déjà supprimées pour la permission '{permission}'",
|
"additional_urls_already_removed": "L'URL supplémentaire '{url}' a déjà été supprimée pour la permission '{permission}'",
|
||||||
"invalid_number": "Doit être un nombre",
|
"invalid_number": "Doit être un nombre",
|
||||||
"diagnosis_basesystem_hardware_model": "Le modèle/architecture du serveur est {model}",
|
"diagnosis_basesystem_hardware_model": "Le modèle/architecture du serveur est {model}",
|
||||||
"diagnosis_backports_in_sources_list": "Il semble que le gestionnaire de paquet APT soit configuré pour utiliser le dépôt des rétro-portages (backports). A moins que vous ne sachiez vraiment ce que vous faites, nous vous déconseillons fortement d'installer des paquets provenant du dépôt 'backports', car cela risque de créer des instabilités ou des conflits sur votre système.",
|
"diagnosis_backports_in_sources_list": "Il semble que le gestionnaire de paquet APT soit configuré pour utiliser le dépôt des rétro-portages (backports). A moins que vous ne sachiez vraiment ce que vous faites, nous vous déconseillons fortement d'installer des paquets provenant du dépôt 'backports', car cela risque de créer des instabilités ou des conflits sur votre système.",
|
||||||
|
@ -766,5 +766,21 @@
|
||||||
"group_mailalias_add": "L'alias de courrier électronique '{mail}' sera ajouté au groupe '{group}'",
|
"group_mailalias_add": "L'alias de courrier électronique '{mail}' sera ajouté au groupe '{group}'",
|
||||||
"group_user_add": "L'utilisateur '{user}' sera ajouté au groupe '{group}'",
|
"group_user_add": "L'utilisateur '{user}' sera ajouté au groupe '{group}'",
|
||||||
"group_user_remove": "L'utilisateur '{user}' sera retiré du groupe '{group}'",
|
"group_user_remove": "L'utilisateur '{user}' sera retiré du groupe '{group}'",
|
||||||
"group_mailalias_remove": "L'alias de courrier électronique '{mail}' sera supprimé du groupe '{group}'"
|
"group_mailalias_remove": "L'alias de courrier électronique '{mail}' sera supprimé du groupe '{group}'",
|
||||||
|
"ask_dyndns_recovery_password_explain": "Veuillez choisir un mot de passe de récupération pour votre domaine DynDNS, au cas où vous devriez le réinitialiser plus tard.",
|
||||||
|
"ask_dyndns_recovery_password": "Mot de passe de récupération DynDNS",
|
||||||
|
"ask_dyndns_recovery_password_explain_during_unsubscribe": "Veuillez saisir le mot de passe de récupération pour ce domaine DynDNS.",
|
||||||
|
"dyndns_no_recovery_password": "Aucun mot de passe de récupération n'a été spécifié ! Si vous perdez le contrôle de ce domaine, vous devrez contacter un administrateur de l'équipe YunoHost !",
|
||||||
|
"dyndns_subscribed": "Domaine DynDNS souscrit/enregistré",
|
||||||
|
"dyndns_subscribe_failed": "Impossible de souscrire/de s'enregistrer au domaine DynDNS : {erreur}",
|
||||||
|
"dyndns_unsubscribe_failed": "Impossible de se désinscrire du domaine DynDNS : {erreur}",
|
||||||
|
"dyndns_unsubscribed": "Désinscription du domaine DynDNS",
|
||||||
|
"dyndns_unsubscribe_denied": "Échec de la désinscription du domaine : informations d'identification non valides",
|
||||||
|
"dyndns_unsubscribe_already_unsubscribed": "Le domaine est déjà désabonné/retiré",
|
||||||
|
"dyndns_set_recovery_password_denied": "Échec de la définition du mot de passe de récupération : mot de passe non valide",
|
||||||
|
"dyndns_set_recovery_password_unknown_domain": "Échec de la définition du mot de passe de récupération : le domaine n'est pas enregistré",
|
||||||
|
"dyndns_set_recovery_password_invalid_password": "Échec de la définition du mot de passe de récupération : le mot de passe n'est pas assez fort/solide",
|
||||||
|
"dyndns_set_recovery_password_failed": "Échec de la définition du mot de passe de récupération : {erreur}",
|
||||||
|
"dyndns_set_recovery_password_success": "Mot de passe de récupération défini/configuré !",
|
||||||
|
"log_dyndns_unsubscribe": "Se désabonner d'un sous-domaine YunoHost '{}'"
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,7 +612,7 @@
|
||||||
"domain_config_auth_consumer_key": "Chave consumidora",
|
"domain_config_auth_consumer_key": "Chave consumidora",
|
||||||
"log_domain_dns_push": "Enviar rexistros DNS para o dominio '{}'",
|
"log_domain_dns_push": "Enviar rexistros DNS para o dominio '{}'",
|
||||||
"other_available_options": "... e outras {n} opcións dispoñibles non mostradas",
|
"other_available_options": "... e outras {n} opcións dispoñibles non mostradas",
|
||||||
"domain_dns_registrar_yunohost": "Este dominio un dos de nohost.me / nohost.st / ynh.fr e a configuración DNS xestionaa directamente YunoHost se máis requisitos. (mira o comando 'yunohost dyndns update')",
|
"domain_dns_registrar_yunohost": "Este dominio é un dos de nohost.me / nohost.st / ynh.fr e a configuración DNS xestionaa directamente YunoHost sen máis requisitos. (mira o comando 'yunohost dyndns update')",
|
||||||
"domain_dns_registrar_supported": "YunoHost detectou automáticamente que este dominio está xestionado pola rexistradora **{registrar}**. Se queres, YunoHost pode configurar automáticamente as súas zonas DNS, se proporcionas as credenciais de acceso á API. Podes ver a documentación sobre como obter as credenciais da API nesta páxina: https://yunohost.org/registrar_api_{registrar}. (Tamén podes configurar manualmente os rexistros DNS seguindo a documentación en https://yunohost.org/dns )",
|
"domain_dns_registrar_supported": "YunoHost detectou automáticamente que este dominio está xestionado pola rexistradora **{registrar}**. Se queres, YunoHost pode configurar automáticamente as súas zonas DNS, se proporcionas as credenciais de acceso á API. Podes ver a documentación sobre como obter as credenciais da API nesta páxina: https://yunohost.org/registrar_api_{registrar}. (Tamén podes configurar manualmente os rexistros DNS seguindo a documentación en https://yunohost.org/dns )",
|
||||||
"domain_dns_push_partial_failure": "Actualización parcial dos rexistros DNS: informouse dalgúns avisos/erros.",
|
"domain_dns_push_partial_failure": "Actualización parcial dos rexistros DNS: informouse dalgúns avisos/erros.",
|
||||||
"domain_config_auth_token": "Token de autenticación",
|
"domain_config_auth_token": "Token de autenticación",
|
||||||
|
@ -654,7 +654,7 @@
|
||||||
"global_settings_setting_admin_strength": "Fortaleza do contrasinal de Admin",
|
"global_settings_setting_admin_strength": "Fortaleza do contrasinal de Admin",
|
||||||
"global_settings_setting_user_strength": "Fortaleza do contrasinal da usuaria",
|
"global_settings_setting_user_strength": "Fortaleza do contrasinal da usuaria",
|
||||||
"global_settings_setting_postfix_compatibility_help": "Compromiso entre compatibilidade e seguridade para o servidor Postfix. Aféctalle ao cifrado (e outros aspectos da seguridade)",
|
"global_settings_setting_postfix_compatibility_help": "Compromiso entre compatibilidade e seguridade para o servidor Postfix. Aféctalle ao cifrado (e outros aspectos da seguridade)",
|
||||||
"global_settings_setting_ssh_compatibility_help": "Compromiso entre compatibilidade e seguridade para o servidor SSH. Aféctalle ao cifrado (e outros aspectos da seguridade)",
|
"global_settings_setting_ssh_compatibility_help": "Compromiso entre compatibilidade e seguridade para o servidor SSH. Aféctalle ao cifrado (e outros aspectos da seguridade). Le https://infosec.mozilla.org/guidelines/openssh for more info.",
|
||||||
"global_settings_setting_ssh_password_authentication_help": "Permitir autenticación con contrasinal para SSH",
|
"global_settings_setting_ssh_password_authentication_help": "Permitir autenticación con contrasinal para SSH",
|
||||||
"global_settings_setting_ssh_port": "Porto SSH",
|
"global_settings_setting_ssh_port": "Porto SSH",
|
||||||
"global_settings_setting_webadmin_allowlist_help": "Enderezos IP con permiso para acceder á webadmin. Separados por vírgulas.",
|
"global_settings_setting_webadmin_allowlist_help": "Enderezos IP con permiso para acceder á webadmin. Separados por vírgulas.",
|
||||||
|
@ -766,5 +766,21 @@
|
||||||
"group_mailalias_add": "Vaise engadir o alias de correo '{mail}' ao grupo '{group}'",
|
"group_mailalias_add": "Vaise engadir o alias de correo '{mail}' ao grupo '{group}'",
|
||||||
"group_mailalias_remove": "Vaise quitar o alias de email '{mail}' do grupo '{group}'",
|
"group_mailalias_remove": "Vaise quitar o alias de email '{mail}' do grupo '{group}'",
|
||||||
"group_user_add": "Vaise engadir a '{user}' ao grupo '{grupo}'",
|
"group_user_add": "Vaise engadir a '{user}' ao grupo '{grupo}'",
|
||||||
"group_user_remove": "Vaise quitar a '{user}' do grupo '{grupo}'"
|
"group_user_remove": "Vaise quitar a '{user}' do grupo '{grupo}'",
|
||||||
|
"ask_dyndns_recovery_password_explain": "Elixe un contrasinal de recuperación para o teu dominio DynDNS, por se precisas restablecelo no futuro.",
|
||||||
|
"ask_dyndns_recovery_password": "Contrasinal de recuperación DynDNS",
|
||||||
|
"ask_dyndns_recovery_password_explain_during_unsubscribe": "Escribe o contrasinal de recuperación para este dominio DynDNS.",
|
||||||
|
"dyndns_no_recovery_password": "Non se estableceu un contrasinal de recuperación! Se perdes o control sobre dominio precisarás contactar coa administración do equipo YunoHost!",
|
||||||
|
"dyndns_subscribed": "Tes unha subscrición a un dominio DynDNS",
|
||||||
|
"dyndns_subscribe_failed": "Non te subscribiches ao dominio DynDNS: {error}",
|
||||||
|
"dyndns_unsubscribe_failed": "Non se retirou a subscrición ao dominio DynDNS: {error}",
|
||||||
|
"dyndns_unsubscribed": "Retirada a subscrición ao dominio DynDNS",
|
||||||
|
"dyndns_unsubscribe_denied": "Fallo ao intentar retirar subscrición: credenciais incorrectas",
|
||||||
|
"dyndns_unsubscribe_already_unsubscribed": "Non tes unha subscrición ao dominio",
|
||||||
|
"dyndns_set_recovery_password_denied": "Fallou o establecemento do contrasinal de recuperación: chave non válida",
|
||||||
|
"dyndns_set_recovery_password_unknown_domain": "Fallo ao establecer o contrasinal de recuperación: dominio non rexistrado",
|
||||||
|
"dyndns_set_recovery_password_invalid_password": "Fallo ao establecer contrasinal de recuperación: o contrasinal non é suficientemente forte",
|
||||||
|
"dyndns_set_recovery_password_failed": "Fallo ao establecer o contrasinal de recuperación: {error}",
|
||||||
|
"dyndns_set_recovery_password_success": "Estableceuse o contrasinal de recuperación!",
|
||||||
|
"log_dyndns_unsubscribe": "Retirar subscrición para o subdominio YunoHost '{}'"
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,5 +391,54 @@
|
||||||
"log_letsencrypt_cert_renew": "Memperbarui sertifikat Let's Encrypt '{}'",
|
"log_letsencrypt_cert_renew": "Memperbarui sertifikat Let's Encrypt '{}'",
|
||||||
"log_selfsigned_cert_install": "Memasang sertifikat ditandai sendiri pada domain '{}'",
|
"log_selfsigned_cert_install": "Memasang sertifikat ditandai sendiri pada domain '{}'",
|
||||||
"log_user_permission_reset": "Mengatur ulang izin '{}'",
|
"log_user_permission_reset": "Mengatur ulang izin '{}'",
|
||||||
"domain_config_xmpp": "Pesan Langsung (XMPP)"
|
"domain_config_xmpp": "Pesan Langsung (XMPP)",
|
||||||
|
"diagnosis_http_connection_error": "Masalah jaringan: tidak dapat terhubung dengan domain yang diminta, sangat mungkin terputus.",
|
||||||
|
"dyndns_ip_updated": "IP Anda diperbarui di DynDNS",
|
||||||
|
"ask_dyndns_recovery_password_explain": "Pilih kata sandi pemulihan untuk domain DynDNS Anda.",
|
||||||
|
"ask_dyndns_recovery_password": "Kata sandi pemulihan DynDNS",
|
||||||
|
"backup_output_directory_not_empty": "Anda harus memilih direktori yang kosong",
|
||||||
|
"service_reload_or_restart_failed": "Tidak dapat memuat atau memulai ulang layanan '{service}'\n\nLog layanan baru-baru ini:{logs}",
|
||||||
|
"service_reload_failed": "Tidak dapat memuat ulang layanan '{service}'\n\nLog layanan baru-baru ini:{logs}",
|
||||||
|
"service_start_failed": "Tidak dapat memulai layanan '{service}'\n\nLog layanan baru-baru ini: {logs}",
|
||||||
|
"diagnosis_apps_deprecated_practices": "Versi aplikasi yang dipasang ini masih menggunakan praktik pengemasan yang lama. Anda lebih baik untuk memperbarui aplikasi tersebut.",
|
||||||
|
"diagnosis_dns_bad_conf": "Beberapa rekaman DNS untuk domain {domain} ada yang tidak ada atau salah (kategori {category})",
|
||||||
|
"diagnosis_dns_good_conf": "Rekaman DNS untuk domain {domain} sudah diatur dengan benar (kategori {category})",
|
||||||
|
"dyndns_unavailable": "Domain '{domain}' tidak tersedia.",
|
||||||
|
"dyndns_set_recovery_password_denied": "Tidak dapat menyetel kata sandi pemulihan: tidak valid",
|
||||||
|
"dyndns_set_recovery_password_unknown_domain": "Tidak dapat menyetel kata sandi pemulihan: domain belum terdaftar",
|
||||||
|
"dyndns_set_recovery_password_invalid_password": "Tidak dapat menyetel kata sandi pemulihan: kata sandi tidak cukup kuat",
|
||||||
|
"dyndns_set_recovery_password_failed": "Tidak dapat menyetel kata sandi pemulihan: {error}",
|
||||||
|
"dyndns_set_recovery_password_success": "Kata sandi pemulihan berhasil disetel!",
|
||||||
|
"file_does_not_exist": "Berkas {path} tidak ada.",
|
||||||
|
"firewall_reload_failed": "Tidak dapat memuat ulang tembok api",
|
||||||
|
"firewall_reloaded": "Tembok api dimuat ulang",
|
||||||
|
"migration_description_0023_postgresql_11_to_13": "Migrasi basis data dari PostgreSQL 11 ke 13",
|
||||||
|
"service_enabled": "Layanan '{service}' akan secara mandiri dimulai saat pemulaian.",
|
||||||
|
"service_reloaded_or_restarted": "Layanan {service} dimuat atau dimulai ulang",
|
||||||
|
"service_stopped": "Layanan '{service}' diberhentikan",
|
||||||
|
"service_unknown": "Layanan yang tidak diketahui: '{service}'",
|
||||||
|
"updating_apt_cache": "Mengambil pembaruan yang tersedia untuk paket sistem...",
|
||||||
|
"group_mailalias_remove": "Alias surel '{mail}' akan dihapus dari kelompok '{group}'",
|
||||||
|
"migration_description_0021_migrate_to_bullseye": "Peningkatan sistem ke Debian Bullseye dan YunoHost 11.x",
|
||||||
|
"migration_description_0024_rebuild_python_venv": "Memperbaiki aplikasi Python setelah migrasi Bullseye",
|
||||||
|
"service_disable_failed": "Tidak dapat membuat layanan '{service}' dimulai saat pemulaian.\n\nLog layanan baru-baru ini:{logs}",
|
||||||
|
"service_disabled": "Layanan '{service}' tidak akan dimulai kembali saat pemulaian.",
|
||||||
|
"tools_upgrade_failed": "Tidak dapat memperbarui paket: {packages_list}",
|
||||||
|
"global_settings_setting_nginx_redirect_to_https": "Paksa HTTPS",
|
||||||
|
"backup_archive_system_part_not_available": "Segmen '{part}' tidak tersedia di cadangan ini",
|
||||||
|
"backup_output_directory_forbidden": "Pilih direktori yang berbeda. Cadangan tidak dapat dibuat di /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var, atau subfolder dari /home/yunohost.backup/archives",
|
||||||
|
"ask_dyndns_recovery_password_explain_during_unsubscribe": "Masukkan kata sandi pemulihan untuk domain DynDNS ini.",
|
||||||
|
"backup_output_symlink_dir_broken": "Direktori arsip Anda '{path}' rusak penautannya. Mungkin Anda lupa untuk menambatkan ulang atau memasukkan kembali penyimpanan tujuan penautan direktori arsip tersebut.",
|
||||||
|
"diagnosis_apps_not_in_app_catalog": "Aplikasi ini tidak ada di katalog aplikasi YunoHost. Jika aplikasi ini ada di sana sebelumnya dan dihapus, Anda disarankan untuk melepas aplikasi ini dikarenakan ini tidak akan menerima pembaruan dan mungkin bisa menghancurkan integritas dan keamanan sistem Anda.",
|
||||||
|
"dyndns_ip_update_failed": "Tidak dapat memperbarui IP Anda di DynDNS",
|
||||||
|
"service_restarted": "Layanan {service} dimulai ulang",
|
||||||
|
"service_started": "Layanan '{service}' dimulai",
|
||||||
|
"service_stop_failed": "Tidak dapat menghentikan layanan '{service}'\n\nLog layanan baru-baru ini: {logs}",
|
||||||
|
"apps_catalog_failed_to_download": "Tidak dapat mengunduh katalog aplikasi {apps_catalog}: {error}",
|
||||||
|
"backup_archive_corrupted": "Sepertinya arsip cadangan '{archive}' rusak: {error}",
|
||||||
|
"diagnosis_found_errors": "{errors} masalah signifikan ditemukan terkait dengan {category}!",
|
||||||
|
"restore_system_part_failed": "Tidak dapat memulihkan segmen '{part}'",
|
||||||
|
"service_enable_failed": "Tidak dapat membuat layanan '{service}' dimulai mandiri saat pemulaian.\n\nLog layanan baru-baru ini:{logs}",
|
||||||
|
"service_not_reloading_because_conf_broken": "Tidak memuat atau memulai ulang layanan '{name}' karena konfigurasinya rusak: {errors}",
|
||||||
|
"service_reloaded": "Layanan {service} dimuat ulang"
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@
|
||||||
"backup_applying_method_custom": "Wywołuję niestandardową metodę tworzenia kopii zapasowych '{method}'...",
|
"backup_applying_method_custom": "Wywołuję niestandardową metodę tworzenia kopii zapasowych '{method}'...",
|
||||||
"app_remove_after_failed_install": "Usuwanie aplikacji po niepowodzeniu instalacji...",
|
"app_remove_after_failed_install": "Usuwanie aplikacji po niepowodzeniu instalacji...",
|
||||||
"app_upgrade_script_failed": "Wystąpił błąd w skrypcie aktualizacji aplikacji",
|
"app_upgrade_script_failed": "Wystąpił błąd w skrypcie aktualizacji aplikacji",
|
||||||
"apps_catalog_init_success": "Zainicjowano system katalogu aplikacji!",
|
"apps_catalog_init_success": "System katalogu aplikacji został zainicjowany!",
|
||||||
"apps_catalog_obsolete_cache": "Pamięć podręczna katalogu aplikacji jest pusta lub przestarzała.",
|
"apps_catalog_obsolete_cache": "Pamięć podręczna katalogu aplikacji jest pusta lub przestarzała.",
|
||||||
"app_extraction_failed": "Nie można wyodrębnić plików instalacyjnych",
|
"app_extraction_failed": "Nie można wyodrębnić plików instalacyjnych",
|
||||||
"app_packaging_format_not_supported": "Ta aplikacja nie może zostać zainstalowana, ponieważ jej format opakowania nie jest obsługiwany przez twoją wersję YunoHost. Prawdopodobnie powinieneś rozważyć aktualizację swojego systemu.",
|
"app_packaging_format_not_supported": "Ta aplikacja nie może zostać zainstalowana, ponieważ jej format opakowania nie jest obsługiwany przez twoją wersję YunoHost. Prawdopodobnie powinieneś rozważyć aktualizację swojego systemu.",
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
"app_failed_to_download_asset": "Nie udało się pobrać zasobu '{source_id}' ({url}) dla {app}: {out}",
|
"app_failed_to_download_asset": "Nie udało się pobrać zasobu '{source_id}' ({url}) dla {app}: {out}",
|
||||||
"backup_with_no_backup_script_for_app": "Aplikacja '{app}' nie posiada skryptu kopii zapasowej. Ignorowanie.",
|
"backup_with_no_backup_script_for_app": "Aplikacja '{app}' nie posiada skryptu kopii zapasowej. Ignorowanie.",
|
||||||
"backup_with_no_restore_script_for_app": "Aplikacja {app} nie posiada skryptu przywracania, co oznacza, że nie będzie można automatycznie przywrócić kopii zapasowej tej aplikacji.",
|
"backup_with_no_restore_script_for_app": "Aplikacja {app} nie posiada skryptu przywracania, co oznacza, że nie będzie można automatycznie przywrócić kopii zapasowej tej aplikacji.",
|
||||||
"certmanager_acme_not_configured_for_domain": "Wyzwanie ACME nie może zostać uruchomione dla domeny {domain}, ponieważ jej konfiguracja nginx nie zawiera odpowiedniego fragmentu kodu... Upewnij się, że konfiguracja nginx jest aktualna, używając polecenia yunohost tools regen-conf nginx --dry-run --with-diff.",
|
"certmanager_acme_not_configured_for_domain": "Wyzwanie ACME nie może być teraz uruchomione dla {domain}, ponieważ jego konfiguracja nginx nie zawiera odpowiedniego fragmentu kodu… Upewnij się, że twoja konfiguracja nginx jest aktualna, używając `yunohost tools regen-conf nginx --dry-run --with-diff`.",
|
||||||
"certmanager_domain_dns_ip_differs_from_public_ip": "Rekordy DNS dla domeny '{domain}' różnią się od adresu IP tego serwera. Sprawdź kategorię 'Rekordy DNS' (podstawowe) w diagnozie, aby uzyskać więcej informacji. Jeśli niedawno dokonałeś zmiany rekordu A, poczekaj, aż zostanie on zaktualizowany (można skorzystać z narzędzi online do sprawdzania propagacji DNS). (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
"certmanager_domain_dns_ip_differs_from_public_ip": "Rekordy DNS dla domeny '{domain}' różnią się od adresu IP tego serwera. Sprawdź kategorię 'Rekordy DNS' (podstawowe) w diagnozie, aby uzyskać więcej informacji. Jeśli niedawno dokonałeś zmiany rekordu A, poczekaj, aż zostanie on zaktualizowany (można skorzystać z narzędzi online do sprawdzania propagacji DNS). (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
||||||
"confirm_app_install_danger": "UWAGA! Ta aplikacja jest wciąż w fazie eksperymentalnej (jeśli nie działa jawnie)! Prawdopodobnie NIE powinieneś jej instalować, chyba że wiesz, co robisz. NIE ZOSTANIE udzielone wsparcie, jeśli ta aplikacja nie będzie działać poprawnie lub spowoduje uszkodzenie systemu... Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}",
|
"confirm_app_install_danger": "UWAGA! Ta aplikacja jest wciąż w fazie eksperymentalnej (jeśli nie działa jawnie)! Prawdopodobnie NIE powinieneś jej instalować, chyba że wiesz, co robisz. NIE ZOSTANIE udzielone wsparcie, jeśli ta aplikacja nie będzie działać poprawnie lub spowoduje uszkodzenie systemu... Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}",
|
||||||
"confirm_app_install_thirdparty": "UWAGA! Ta aplikacja nie jest częścią katalogu aplikacji YunoHost. Instalowanie aplikacji innych firm może naruszyć integralność i bezpieczeństwo systemu. Prawdopodobnie NIE powinieneś jej instalować, chyba że wiesz, co robisz. NIE ZOSTANIE udzielone wsparcie, jeśli ta aplikacja nie będzie działać poprawnie lub spowoduje uszkodzenie systemu... Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}'",
|
"confirm_app_install_thirdparty": "UWAGA! Ta aplikacja nie jest częścią katalogu aplikacji YunoHost. Instalowanie aplikacji innych firm może naruszyć integralność i bezpieczeństwo systemu. Prawdopodobnie NIE powinieneś jej instalować, chyba że wiesz, co robisz. NIE ZOSTANIE udzielone wsparcie, jeśli ta aplikacja nie będzie działać poprawnie lub spowoduje uszkodzenie systemu... Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}'",
|
||||||
|
@ -192,19 +192,19 @@
|
||||||
"config_no_panel": "Nie znaleziono panelu konfiguracji.",
|
"config_no_panel": "Nie znaleziono panelu konfiguracji.",
|
||||||
"config_unknown_filter_key": "Klucz filtru '{filter_key}' jest niepoprawny.",
|
"config_unknown_filter_key": "Klucz filtru '{filter_key}' jest niepoprawny.",
|
||||||
"config_validate_email": "Proszę podać poprawny adres e-mail",
|
"config_validate_email": "Proszę podać poprawny adres e-mail",
|
||||||
"backup_hook_unknown": "Nieznany jest hook kopii zapasowej '{hook}'.",
|
"backup_hook_unknown": "Nieznany jest hook kopii zapasowej '{hook}'",
|
||||||
"backup_no_uncompress_archive_dir": "Nie istnieje taki katalog nieskompresowanego archiwum.",
|
"backup_no_uncompress_archive_dir": "Nie istnieje taki katalog nieskompresowanego archiwum",
|
||||||
"backup_output_symlink_dir_broken": "Twój katalog archiwum '{path}' to uszkodzony dowiązanie symboliczne. Być może zapomniałeś o ponownym zamontowaniu lub podłączeniu nośnika przechowującego, do którego on wskazuje.",
|
"backup_output_symlink_dir_broken": "Twój katalog archiwum ‘{path}’ to uszkodzony symlink. Być może zapomniałeś o ponownym zamontowaniu lub podłączeniu nośnika przechowującego, do którego on wskazuje.",
|
||||||
"backup_system_part_failed": "Nie można wykonać kopii zapasowej części systemu '{part}'",
|
"backup_system_part_failed": "Nie udało się wykonać kopii zapasowej części systemu ‘{part}’",
|
||||||
"config_validate_color": "Powinien być poprawnym szesnastkowym kodem koloru RGB.",
|
"config_validate_color": "Powinien być poprawnym szesnastkowym kodem koloru RGB.",
|
||||||
"config_validate_date": "Data powinna być poprawna w formacie RRRR-MM-DD",
|
"config_validate_date": "Data powinna być poprawna w formacie RRRR-MM-DD",
|
||||||
"config_validate_time": "Podaj poprawny czas w formacie GG:MM",
|
"config_validate_time": "Podaj poprawny czas w formacie GG:MM",
|
||||||
"certmanager_domain_not_diagnosed_yet": "Nie ma jeszcze wyników diagnozy dla domeny {domain}. Proszę ponownie uruchomić diagnozę dla kategorii 'Rekordy DNS' i 'Strona internetowa' w sekcji diagnozy, aby sprawdzić, czy domena jest gotowa do użycia Let's Encrypt. (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
"certmanager_domain_not_diagnosed_yet": "Nie ma jeszcze wyników diagnozy dla domeny {domain}. Proszę ponownie uruchomić diagnozę dla kategorii 'Rekordy DNS' i 'Strona internetowa' w sekcji diagnozy, aby sprawdzić, czy domena jest gotowa do użycia Let's Encrypt. (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
||||||
"certmanager_cannot_read_cert": "Wystąpił problem podczas próby otwarcia bieżącego certyfikatu dla domeny {domain} (plik: {file}), przyczyna: {reason}",
|
"certmanager_cannot_read_cert": "Wystąpił problem podczas próby otwarcia bieżącego certyfikatu dla domeny {domain} (plik: {file}), przyczyna: {reason}",
|
||||||
"certmanager_no_cert_file": "Nie można odczytać pliku certyfikatu dla domeny {domain} (plik: {file}).",
|
"certmanager_no_cert_file": "Nie można odczytać pliku certyfikatu dla domeny {domain} (plik: {file})",
|
||||||
"certmanager_self_ca_conf_file_not_found": "Nie można znaleźć pliku konfiguracyjnego dla autorytetu samopodpisującego (plik: {file})",
|
"certmanager_self_ca_conf_file_not_found": "Nie można znaleźć pliku konfiguracyjnego dla samodzielnie podpisanego upoważnienia do (file: {file})",
|
||||||
"backup_running_hooks": "Uruchamianie hooków kopii zapasowej...",
|
"backup_running_hooks": "Uruchamianie kopii zapasowej hooków...",
|
||||||
"backup_permission": "Uprawnienia kopii zapasowej dla aplikacji {app}",
|
"backup_permission": "Uprawnienia do tworzenia kopii zapasowej dla aplikacji {app}",
|
||||||
"certmanager_domain_cert_not_selfsigned": "Certyfikat dla domeny {domain} nie jest samopodpisany. Czy na pewno chcesz go zastąpić? (Użyj opcji '--force', aby to zrobić.)",
|
"certmanager_domain_cert_not_selfsigned": "Certyfikat dla domeny {domain} nie jest samopodpisany. Czy na pewno chcesz go zastąpić? (Użyj opcji '--force', aby to zrobić.)",
|
||||||
"config_action_disabled": "Nie można uruchomić akcji '{action}', ponieważ jest ona wyłączona. Upewnij się, że spełnione są jej ograniczenia. Pomoc: {help}",
|
"config_action_disabled": "Nie można uruchomić akcji '{action}', ponieważ jest ona wyłączona. Upewnij się, że spełnione są jej ograniczenia. Pomoc: {help}",
|
||||||
"config_action_failed": "Nie udało się uruchomić akcji '{action}': {error}",
|
"config_action_failed": "Nie udało się uruchomić akcji '{action}': {error}",
|
||||||
|
@ -214,7 +214,7 @@
|
||||||
"confirm_app_insufficient_ram": "UWAGA! Ta aplikacja wymaga {required} pamięci RAM do zainstalowania/aktualizacji, a obecnie dostępne jest tylko {current}. Nawet jeśli aplikacja mogłaby działać, proces instalacji/aktualizacji wymaga dużej ilości pamięci RAM, więc serwer może się zawiesić i niepowodzenie może być katastrofalne. Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}'",
|
"confirm_app_insufficient_ram": "UWAGA! Ta aplikacja wymaga {required} pamięci RAM do zainstalowania/aktualizacji, a obecnie dostępne jest tylko {current}. Nawet jeśli aplikacja mogłaby działać, proces instalacji/aktualizacji wymaga dużej ilości pamięci RAM, więc serwer może się zawiesić i niepowodzenie może być katastrofalne. Jeśli mimo to jesteś gotów podjąć to ryzyko, wpisz '{answers}'",
|
||||||
"app_not_upgraded_broken_system": "Aplikacja '{failed_app}' nie powiodła się w procesie aktualizacji i spowodowała uszkodzenie systemu. W rezultacie anulowane zostały aktualizacje następujących aplikacji: {apps}",
|
"app_not_upgraded_broken_system": "Aplikacja '{failed_app}' nie powiodła się w procesie aktualizacji i spowodowała uszkodzenie systemu. W rezultacie anulowane zostały aktualizacje następujących aplikacji: {apps}",
|
||||||
"app_not_upgraded_broken_system_continue": "Aplikacja '{failed_app}' nie powiodła się w procesie aktualizacji i spowodowała uszkodzenie systemu (parametr --continue-on-failure jest ignorowany). W rezultacie anulowane zostały aktualizacje następujących aplikacji: {apps}",
|
"app_not_upgraded_broken_system_continue": "Aplikacja '{failed_app}' nie powiodła się w procesie aktualizacji i spowodowała uszkodzenie systemu (parametr --continue-on-failure jest ignorowany). W rezultacie anulowane zostały aktualizacje następujących aplikacji: {apps}",
|
||||||
"certmanager_domain_http_not_working": "Domena {domain} wydaje się niedostępna przez HTTP. Sprawdź kategorię 'Strona internetowa' diagnostyki, aby uzyskać więcej informacji. (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
"certmanager_domain_http_not_working": "Domena {domain} nie wydaje się być dostępna przez HTTP. Sprawdź kategorię 'Strona internetowa' diagnostyki, aby uzyskać więcej informacji. (Jeśli wiesz, co robisz, użyj opcji '--no-checks', aby wyłączyć te sprawdzania.)",
|
||||||
"migration_0021_system_not_fully_up_to_date": "Twój system nie jest w pełni zaktualizowany! Proszę, wykonaj zwykłą aktualizację oprogramowania zanim rozpoczniesz migrację na system Bullseye.",
|
"migration_0021_system_not_fully_up_to_date": "Twój system nie jest w pełni zaktualizowany! Proszę, wykonaj zwykłą aktualizację oprogramowania zanim rozpoczniesz migrację na system Bullseye.",
|
||||||
"global_settings_setting_smtp_relay_port": "Port przekaźnika SMTP",
|
"global_settings_setting_smtp_relay_port": "Port przekaźnika SMTP",
|
||||||
"domain_config_cert_renew": "Odnów certyfikat Let's Encrypt",
|
"domain_config_cert_renew": "Odnów certyfikat Let's Encrypt",
|
||||||
|
@ -274,5 +274,12 @@
|
||||||
"global_settings_setting_smtp_allow_ipv6_help": "Zezwól na wykorzystywanie IPv7 do odbierania i wysyłania maili",
|
"global_settings_setting_smtp_allow_ipv6_help": "Zezwól na wykorzystywanie IPv7 do odbierania i wysyłania maili",
|
||||||
"global_settings_setting_ssh_password_authentication": "Logowanie hasłem",
|
"global_settings_setting_ssh_password_authentication": "Logowanie hasłem",
|
||||||
"diagnosis_backports_in_sources_list": "Wygląda na to że apt (menedżer pakietów) został skonfigurowany tak, aby wykorzystywać repozytorium backported. Nie zalecamy wykorzystywania repozytorium backported, ponieważ może powodować problemy ze stabilnością i/lub konflikty z konfiguracją. No chyba, że wiesz co robisz.",
|
"diagnosis_backports_in_sources_list": "Wygląda na to że apt (menedżer pakietów) został skonfigurowany tak, aby wykorzystywać repozytorium backported. Nie zalecamy wykorzystywania repozytorium backported, ponieważ może powodować problemy ze stabilnością i/lub konflikty z konfiguracją. No chyba, że wiesz co robisz.",
|
||||||
"domain_config_xmpp_help": "Uwaga: niektóre funkcje XMPP będą wymagały aktualizacji rekordów DNS i odnowienia certyfikatu Lets Encrypt w celu ich włączenia"
|
"domain_config_xmpp_help": "Uwaga: niektóre funkcje XMPP będą wymagały aktualizacji rekordów DNS i odnowienia certyfikatu Lets Encrypt w celu ich włączenia",
|
||||||
|
"ask_dyndns_recovery_password_explain": "Proszę wybrać hasło odzyskiwania dla swojej domeny DynDNS, na wypadek gdybyś musiał go później zresetować.",
|
||||||
|
"ask_dyndns_recovery_password_explain_during_unsubscribe": "Proszę wprowadzić hasło odzyskiwania dla tej domeny DynDNS.",
|
||||||
|
"certmanager_unable_to_parse_self_CA_name": "Nie można spasować nazwy organu samopodpisywanego (pliku: {file})",
|
||||||
|
"app_corrupt_source": "YunoHost był w stanie pobrać zasób ‘{source_id}’ ({url}) dla {app}, ale zasób nie pasuje do oczekiwanego sumy kontrolnej. Może to oznaczać, że na twoim serwerze wystąpiła tymczasowa awaria sieci, LUB zasób został jakoś zmieniony przez dostawcę usługi (lub złośliwego aktora?) i pakowacze YunoHost muszą zbadać sprawę i zaktualizować manifest aplikacji, aby odzwierciedlić tę zmianę. \nOczekiwana suma kontrolna sha256: {expected_sha256} \nPobrana suma kontrolna sha256: {computed_sha256} \nRozmiar pobranego pliku: {size}”",
|
||||||
|
"ask_dyndns_recovery_password": "Hasło odzyskiwania DynDNS",
|
||||||
|
"certmanager_hit_rate_limit": "Zbyt wiele certyfikatów zostało ostatnio wydanych dla tej dokładnej grupy domen {domain}. Spróbuj ponownie później. Zobacz https://letsencrypt.org/docs/rate-limits/ aby uzyskać więcej informacji",
|
||||||
|
"apps_failed_to_upgrade_line": "\n * {app_id} (aby zobaczyć odpowiedni dziennik, wykonaj ‘yunohost log show {operation_logger_name}’)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,5 +15,10 @@
|
||||||
"additional_urls_already_added": "Ek URL '{url}' zaten '{permission}' izni için ek URL'ye eklendi",
|
"additional_urls_already_added": "Ek URL '{url}' zaten '{permission}' izni için ek URL'ye eklendi",
|
||||||
"additional_urls_already_removed": "Ek URL '{url}', '{permission}' izni için ek URL'de zaten kaldırıldı",
|
"additional_urls_already_removed": "Ek URL '{url}', '{permission}' izni için ek URL'de zaten kaldırıldı",
|
||||||
"app_action_cannot_be_ran_because_required_services_down": "Bu eylemi gerçekleştirmek için şu servisler çalışıyor olmalıdır: {services}. Devam etmek için onları yeniden başlatın (ve muhtemelen neden çalışmadığını araştırın).",
|
"app_action_cannot_be_ran_because_required_services_down": "Bu eylemi gerçekleştirmek için şu servisler çalışıyor olmalıdır: {services}. Devam etmek için onları yeniden başlatın (ve muhtemelen neden çalışmadığını araştırın).",
|
||||||
"app_arch_not_supported": "Bu uygulama yalnızca {required} işlemci mimarisi üzerine kurulabilir ancak sunucunuzun işlemci mimarisi {current}."
|
"app_arch_not_supported": "Bu uygulama yalnızca {required} işlemci mimarisi üzerine kurulabilir ancak sunucunuzun işlemci mimarisi {current}.",
|
||||||
|
"app_argument_choice_invalid": "'{name}'' için geçerli bir değer giriniz '{value}' mevcut seçimlerin arasında değil ({choices})",
|
||||||
|
"app_change_url_failed": "{app}: {error} için url değiştirilemedi",
|
||||||
|
"app_argument_required": "'{name}' değeri gerekli",
|
||||||
|
"app_argument_invalid": "'{name}': {error} için geçerli bir değer giriniz",
|
||||||
|
"app_argument_password_no_default": "'{name}': çözümlenirken bir hata meydana geldi. Parola argümanı güvenlik nedeniyle varsayılan değer alamaz"
|
||||||
}
|
}
|
|
@ -70,26 +70,10 @@ user:
|
||||||
help: The full name of the user. For example 'Camille Dupont'
|
help: The full name of the user. For example 'Camille Dupont'
|
||||||
extra:
|
extra:
|
||||||
ask: ask_fullname
|
ask: ask_fullname
|
||||||
required: False
|
required: True
|
||||||
pattern: &pattern_fullname
|
pattern: &pattern_fullname
|
||||||
- !!str ^([^\W_]{1,30}[ ,.'-]{0,3})+$
|
- !!str ^([^\W_]{1,30}[ ,.'-]{0,3})+$
|
||||||
- "pattern_fullname"
|
- "pattern_fullname"
|
||||||
-f:
|
|
||||||
full: --firstname
|
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
|
||||||
required: False
|
|
||||||
pattern: &pattern_firstname
|
|
||||||
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
|
||||||
- "pattern_firstname"
|
|
||||||
-l:
|
|
||||||
full: --lastname
|
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
|
||||||
required: False
|
|
||||||
pattern: &pattern_lastname
|
|
||||||
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
|
||||||
- "pattern_lastname"
|
|
||||||
-p:
|
-p:
|
||||||
full: --password
|
full: --password
|
||||||
help: User password
|
help: User password
|
||||||
|
@ -147,16 +131,6 @@ user:
|
||||||
help: The full name of the user. For example 'Camille Dupont'
|
help: The full name of the user. For example 'Camille Dupont'
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_fullname
|
pattern: *pattern_fullname
|
||||||
-f:
|
|
||||||
full: --firstname
|
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_firstname
|
|
||||||
-l:
|
|
||||||
full: --lastname
|
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_lastname
|
|
||||||
-m:
|
-m:
|
||||||
full: --mail
|
full: --mail
|
||||||
extra:
|
extra:
|
||||||
|
@ -554,17 +528,6 @@ domain:
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_password
|
pattern: *pattern_password
|
||||||
|
|
||||||
|
|
||||||
### domain_dns_conf()
|
|
||||||
dns-conf:
|
|
||||||
deprecated: true
|
|
||||||
action_help: Generate sample DNS configuration for a domain
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Target domain
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_domain
|
|
||||||
|
|
||||||
### domain_maindomain()
|
### domain_maindomain()
|
||||||
main-domain:
|
main-domain:
|
||||||
action_help: Check the current main domain, or change it
|
action_help: Check the current main domain, or change it
|
||||||
|
@ -578,54 +541,6 @@ domain:
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_domain
|
pattern: *pattern_domain
|
||||||
|
|
||||||
### certificate_status()
|
|
||||||
cert-status:
|
|
||||||
deprecated: true
|
|
||||||
action_help: List status of current certificates (all by default).
|
|
||||||
arguments:
|
|
||||||
domain_list:
|
|
||||||
help: Domains to check
|
|
||||||
nargs: "*"
|
|
||||||
--full:
|
|
||||||
help: Show more details
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### certificate_install()
|
|
||||||
cert-install:
|
|
||||||
deprecated: true
|
|
||||||
action_help: Install Let's Encrypt certificates for given domains (all by default).
|
|
||||||
arguments:
|
|
||||||
domain_list:
|
|
||||||
help: Domains for which to install the certificates
|
|
||||||
nargs: "*"
|
|
||||||
--force:
|
|
||||||
help: Install even if current certificate is not self-signed
|
|
||||||
action: store_true
|
|
||||||
--no-checks:
|
|
||||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to install. (Not recommended)
|
|
||||||
action: store_true
|
|
||||||
--self-signed:
|
|
||||||
help: Install self-signed certificate instead of Let's Encrypt
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### certificate_renew()
|
|
||||||
cert-renew:
|
|
||||||
deprecated: true
|
|
||||||
action_help: Renew the Let's Encrypt certificates for given domains (all by default).
|
|
||||||
arguments:
|
|
||||||
domain_list:
|
|
||||||
help: Domains for which to renew the certificates
|
|
||||||
nargs: "*"
|
|
||||||
--force:
|
|
||||||
help: Ignore the validity threshold (30 days)
|
|
||||||
action: store_true
|
|
||||||
--email:
|
|
||||||
help: Send an email to root with logs if some renewing fails
|
|
||||||
action: store_true
|
|
||||||
--no-checks:
|
|
||||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### domain_url_available()
|
### domain_url_available()
|
||||||
url-available:
|
url-available:
|
||||||
hide_in_help: True
|
hide_in_help: True
|
||||||
|
@ -934,14 +849,14 @@ app:
|
||||||
help: Custom name for the app
|
help: Custom name for the app
|
||||||
-a:
|
-a:
|
||||||
full: --args
|
full: --args
|
||||||
help: Serialized arguments for app script (i.e. "domain=domain.tld&path=/path")
|
help: Serialized arguments for app script (i.e. "domain=domain.tld&path=/path&init_main_permission=visitors")
|
||||||
-n:
|
-n:
|
||||||
full: --no-remove-on-failure
|
full: --no-remove-on-failure
|
||||||
help: Debug option to avoid removing the app on a failed installation
|
help: Debug option to avoid removing the app on a failed installation
|
||||||
action: store_true
|
action: store_true
|
||||||
-f:
|
-f:
|
||||||
full: --force
|
full: --force
|
||||||
help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party)
|
help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party), or when the app displays a post-install notification
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
### app_remove()
|
### app_remove()
|
||||||
|
@ -980,7 +895,7 @@ app:
|
||||||
action: store_true
|
action: store_true
|
||||||
-c:
|
-c:
|
||||||
full: --continue-on-failure
|
full: --continue-on-failure
|
||||||
help: Continue to upgrade apps event if one or more upgrade failed
|
help: Continue to upgrade apps even if one or more upgrade failed
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
### app_change_url()
|
### app_change_url()
|
||||||
|
|
|
@ -227,7 +227,7 @@
|
||||||
redact = true
|
redact = true
|
||||||
|
|
||||||
[gandi.api_protocol]
|
[gandi.api_protocol]
|
||||||
type = "string"
|
type = "select"
|
||||||
choices.rpc = "RPC"
|
choices.rpc = "RPC"
|
||||||
choices.rest = "REST"
|
choices.rest = "REST"
|
||||||
default = "rest"
|
default = "rest"
|
||||||
|
|
|
@ -144,17 +144,11 @@ def init_logging(interface="cli", debug=False, quiet=False, logdir="/var/log/yun
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": True,
|
"disable_existing_loggers": True,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
"console": {
|
"tty-debug": {
|
||||||
"format": "%(relativeCreated)-5d %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s"
|
"format": "%(relativeCreated)-4d %(level_with_color)s %(message)s"
|
||||||
},
|
},
|
||||||
"tty-debug": {"format": "%(relativeCreated)-4d %(fmessage)s"},
|
|
||||||
"precise": {
|
"precise": {
|
||||||
"format": "%(asctime)-15s %(levelname)-8s %(name)s %(funcName)s - %(fmessage)s"
|
"format": "%(asctime)-15s %(levelname)-8s %(name)s.%(funcName)s - %(message)s"
|
||||||
},
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"action": {
|
|
||||||
"()": "moulinette.utils.log.ActionFilter",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"handlers": {
|
"handlers": {
|
||||||
|
@ -175,7 +169,6 @@ def init_logging(interface="cli", debug=False, quiet=False, logdir="/var/log/yun
|
||||||
"class": "logging.FileHandler",
|
"class": "logging.FileHandler",
|
||||||
"formatter": "precise",
|
"formatter": "precise",
|
||||||
"filename": logfile,
|
"filename": logfile,
|
||||||
"filters": ["action"],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"loggers": {
|
"loggers": {
|
||||||
|
|
266
src/app.py
266
src/app.py
|
@ -28,9 +28,9 @@ import tempfile
|
||||||
import copy
|
import copy
|
||||||
from typing import List, Tuple, Dict, Any, Iterator, Optional
|
from typing import List, Tuple, Dict, Any, Iterator, Optional
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.process import run_commands, check_output
|
from moulinette.utils.process import run_commands, check_output
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
read_file,
|
read_file,
|
||||||
|
@ -71,7 +71,7 @@ from yunohost.app_catalog import ( # noqa
|
||||||
APPS_CATALOG_LOGOS,
|
APPS_CATALOG_LOGOS,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.app")
|
logger = getLogger("yunohost.app")
|
||||||
|
|
||||||
APPS_SETTING_PATH = "/etc/yunohost/apps/"
|
APPS_SETTING_PATH = "/etc/yunohost/apps/"
|
||||||
APP_TMP_WORKDIRS = "/var/cache/yunohost/app_tmp_work_dirs"
|
APP_TMP_WORKDIRS = "/var/cache/yunohost/app_tmp_work_dirs"
|
||||||
|
@ -186,11 +186,17 @@ def app_info(app, full=False, upgradable=False):
|
||||||
ret["from_catalog"] = from_catalog
|
ret["from_catalog"] = from_catalog
|
||||||
|
|
||||||
# Hydrate app notifications and doc
|
# Hydrate app notifications and doc
|
||||||
|
rendered_doc = {}
|
||||||
for pagename, content_per_lang in ret["manifest"]["doc"].items():
|
for pagename, content_per_lang in ret["manifest"]["doc"].items():
|
||||||
for lang, content in content_per_lang.items():
|
for lang, content in content_per_lang.items():
|
||||||
ret["manifest"]["doc"][pagename][lang] = _hydrate_app_template(
|
rendered_content = _hydrate_app_template(content, settings)
|
||||||
content, settings
|
# Rendered content may be empty because of conditional blocks
|
||||||
)
|
if not rendered_content:
|
||||||
|
continue
|
||||||
|
if pagename not in rendered_doc:
|
||||||
|
rendered_doc[pagename] = {}
|
||||||
|
rendered_doc[pagename][lang] = rendered_content
|
||||||
|
ret["manifest"]["doc"] = rendered_doc
|
||||||
|
|
||||||
# Filter dismissed notification
|
# Filter dismissed notification
|
||||||
ret["manifest"]["notifications"] = {
|
ret["manifest"]["notifications"] = {
|
||||||
|
@ -201,9 +207,16 @@ def app_info(app, full=False, upgradable=False):
|
||||||
|
|
||||||
# Hydrate notifications (also filter uneeded post_upgrade notification based on version)
|
# Hydrate notifications (also filter uneeded post_upgrade notification based on version)
|
||||||
for step, notifications in ret["manifest"]["notifications"].items():
|
for step, notifications in ret["manifest"]["notifications"].items():
|
||||||
|
rendered_notifications = {}
|
||||||
for name, content_per_lang in notifications.items():
|
for name, content_per_lang in notifications.items():
|
||||||
for lang, content in content_per_lang.items():
|
for lang, content in content_per_lang.items():
|
||||||
notifications[name][lang] = _hydrate_app_template(content, settings)
|
rendered_content = _hydrate_app_template(content, settings)
|
||||||
|
if not rendered_content:
|
||||||
|
continue
|
||||||
|
if name not in rendered_notifications:
|
||||||
|
rendered_notifications[name] = {}
|
||||||
|
rendered_notifications[name][lang] = rendered_content
|
||||||
|
ret["manifest"]["notifications"][step] = rendered_notifications
|
||||||
|
|
||||||
ret["is_webapp"] = "domain" in settings and "path" in settings
|
ret["is_webapp"] = "domain" in settings and "path" in settings
|
||||||
|
|
||||||
|
@ -238,8 +251,8 @@ def _app_upgradable(app_infos):
|
||||||
# Determine upgradability
|
# Determine upgradability
|
||||||
|
|
||||||
app_in_catalog = app_infos.get("from_catalog")
|
app_in_catalog = app_infos.get("from_catalog")
|
||||||
installed_version = version.parse(app_infos.get("version", "0~ynh0"))
|
installed_version = _parse_app_version(app_infos.get("version", "0~ynh0"))
|
||||||
version_in_catalog = version.parse(
|
version_in_catalog = _parse_app_version(
|
||||||
app_infos.get("from_catalog", {}).get("manifest", {}).get("version", "0~ynh0")
|
app_infos.get("from_catalog", {}).get("manifest", {}).get("version", "0~ynh0")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -254,25 +267,7 @@ def _app_upgradable(app_infos):
|
||||||
):
|
):
|
||||||
return "bad_quality"
|
return "bad_quality"
|
||||||
|
|
||||||
# If the app uses the standard version scheme, use it to determine
|
if installed_version < version_in_catalog:
|
||||||
# upgradability
|
|
||||||
if "~ynh" in str(installed_version) and "~ynh" in str(version_in_catalog):
|
|
||||||
if installed_version < version_in_catalog:
|
|
||||||
return "yes"
|
|
||||||
else:
|
|
||||||
return "no"
|
|
||||||
|
|
||||||
# Legacy stuff for app with old / non-standard version numbers...
|
|
||||||
|
|
||||||
# In case there is neither update_time nor install_time, we assume the app can/has to be upgraded
|
|
||||||
if not app_infos["from_catalog"].get("lastUpdate") or not app_infos[
|
|
||||||
"from_catalog"
|
|
||||||
].get("git"):
|
|
||||||
return "url_required"
|
|
||||||
|
|
||||||
settings = app_infos["settings"]
|
|
||||||
local_update_time = settings.get("update_time", settings.get("install_time", 0))
|
|
||||||
if app_infos["from_catalog"]["lastUpdate"] > local_update_time:
|
|
||||||
return "yes"
|
return "yes"
|
||||||
else:
|
else:
|
||||||
return "no"
|
return "no"
|
||||||
|
@ -617,9 +612,11 @@ def app_upgrade(
|
||||||
# Manage upgrade type and avoid any upgrade if there is nothing to do
|
# Manage upgrade type and avoid any upgrade if there is nothing to do
|
||||||
upgrade_type = "UNKNOWN"
|
upgrade_type = "UNKNOWN"
|
||||||
# Get current_version and new version
|
# Get current_version and new version
|
||||||
app_new_version = version.parse(manifest.get("version", "?"))
|
app_new_version_raw = manifest.get("version", "?")
|
||||||
app_current_version = version.parse(app_dict.get("version", "?"))
|
app_current_version_raw = app_dict.get("version", "?")
|
||||||
if "~ynh" in str(app_current_version) and "~ynh" in str(app_new_version):
|
app_new_version = _parse_app_version(app_new_version_raw)
|
||||||
|
app_current_version = _parse_app_version(app_current_version_raw)
|
||||||
|
if "~ynh" in str(app_current_version_raw) and "~ynh" in str(app_new_version_raw):
|
||||||
if app_current_version >= app_new_version and not force:
|
if app_current_version >= app_new_version and not force:
|
||||||
# In case of upgrade from file or custom repository
|
# In case of upgrade from file or custom repository
|
||||||
# No new version available
|
# No new version available
|
||||||
|
@ -639,10 +636,10 @@ def app_upgrade(
|
||||||
upgrade_type = "UPGRADE_FORCED"
|
upgrade_type = "UPGRADE_FORCED"
|
||||||
else:
|
else:
|
||||||
app_current_version_upstream, app_current_version_pkg = str(
|
app_current_version_upstream, app_current_version_pkg = str(
|
||||||
app_current_version
|
app_current_version_raw
|
||||||
).split("~ynh")
|
).split("~ynh")
|
||||||
app_new_version_upstream, app_new_version_pkg = str(
|
app_new_version_upstream, app_new_version_pkg = str(
|
||||||
app_new_version
|
app_new_version_raw
|
||||||
).split("~ynh")
|
).split("~ynh")
|
||||||
if app_current_version_upstream == app_new_version_upstream:
|
if app_current_version_upstream == app_new_version_upstream:
|
||||||
upgrade_type = "UPGRADE_PACKAGE"
|
upgrade_type = "UPGRADE_PACKAGE"
|
||||||
|
@ -672,7 +669,7 @@ def app_upgrade(
|
||||||
settings = _get_app_settings(app_instance_name)
|
settings = _get_app_settings(app_instance_name)
|
||||||
notifications = _filter_and_hydrate_notifications(
|
notifications = _filter_and_hydrate_notifications(
|
||||||
manifest["notifications"]["PRE_UPGRADE"],
|
manifest["notifications"]["PRE_UPGRADE"],
|
||||||
current_version=app_current_version,
|
current_version=app_current_version_raw,
|
||||||
data=settings,
|
data=settings,
|
||||||
)
|
)
|
||||||
_display_notifications(notifications, force=force)
|
_display_notifications(notifications, force=force)
|
||||||
|
@ -694,9 +691,17 @@ def app_upgrade(
|
||||||
safety_backup_name = f"{app_instance_name}-pre-upgrade2"
|
safety_backup_name = f"{app_instance_name}-pre-upgrade2"
|
||||||
other_safety_backup_name = f"{app_instance_name}-pre-upgrade1"
|
other_safety_backup_name = f"{app_instance_name}-pre-upgrade1"
|
||||||
|
|
||||||
backup_create(
|
tweaked_backup_core_only = False
|
||||||
name=safety_backup_name, apps=[app_instance_name], system=None
|
if "BACKUP_CORE_ONLY" not in os.environ:
|
||||||
)
|
tweaked_backup_core_only = True
|
||||||
|
os.environ["BACKUP_CORE_ONLY"] = "1"
|
||||||
|
try:
|
||||||
|
backup_create(
|
||||||
|
name=safety_backup_name, apps=[app_instance_name], system=None
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
if tweaked_backup_core_only:
|
||||||
|
del os.environ["BACKUP_CORE_ONLY"]
|
||||||
|
|
||||||
if safety_backup_name in backup_list()["archives"]:
|
if safety_backup_name in backup_list()["archives"]:
|
||||||
# if the backup suceeded, delete old safety backup to save space
|
# if the backup suceeded, delete old safety backup to save space
|
||||||
|
@ -729,8 +734,8 @@ def app_upgrade(
|
||||||
|
|
||||||
env_dict_more = {
|
env_dict_more = {
|
||||||
"YNH_APP_UPGRADE_TYPE": upgrade_type,
|
"YNH_APP_UPGRADE_TYPE": upgrade_type,
|
||||||
"YNH_APP_MANIFEST_VERSION": str(app_new_version),
|
"YNH_APP_MANIFEST_VERSION": str(app_new_version_raw),
|
||||||
"YNH_APP_CURRENT_VERSION": str(app_current_version),
|
"YNH_APP_CURRENT_VERSION": str(app_current_version_raw),
|
||||||
}
|
}
|
||||||
|
|
||||||
if manifest["packaging_format"] < 2:
|
if manifest["packaging_format"] < 2:
|
||||||
|
@ -788,7 +793,7 @@ def app_upgrade(
|
||||||
and not no_safety_backup
|
and not no_safety_backup
|
||||||
):
|
):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Upgrade failed ... attempting to restore the satefy backup (Yunohost first need to remove the app for this) ..."
|
"Upgrade failed ... attempting to restore the safety backup (Yunohost first need to remove the app for this) ..."
|
||||||
)
|
)
|
||||||
|
|
||||||
app_remove(app_instance_name, force_workdir=extracted_app_folder)
|
app_remove(app_instance_name, force_workdir=extracted_app_folder)
|
||||||
|
@ -913,7 +918,7 @@ def app_upgrade(
|
||||||
settings = _get_app_settings(app_instance_name)
|
settings = _get_app_settings(app_instance_name)
|
||||||
notifications = _filter_and_hydrate_notifications(
|
notifications = _filter_and_hydrate_notifications(
|
||||||
manifest["notifications"]["POST_UPGRADE"],
|
manifest["notifications"]["POST_UPGRADE"],
|
||||||
current_version=app_current_version,
|
current_version=app_current_version_raw,
|
||||||
data=settings,
|
data=settings,
|
||||||
)
|
)
|
||||||
if Moulinette.interface.type == "cli":
|
if Moulinette.interface.type == "cli":
|
||||||
|
@ -1098,7 +1103,7 @@ def app_install(
|
||||||
args = {
|
args = {
|
||||||
question.id: question.value
|
question.id: question.value
|
||||||
for question in questions
|
for question in questions
|
||||||
if question.value is not None
|
if not question.readonly and question.value is not None
|
||||||
}
|
}
|
||||||
|
|
||||||
# Validate domain / path availability for webapps
|
# Validate domain / path availability for webapps
|
||||||
|
@ -1157,6 +1162,10 @@ def app_install(
|
||||||
recursive=True,
|
recursive=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Hotfix for bug in the webadmin while we fix the actual issue :D
|
||||||
|
if label == "undefined":
|
||||||
|
label = None
|
||||||
|
|
||||||
# Override manifest name by given label
|
# Override manifest name by given label
|
||||||
# This info is also later picked-up by the 'permission' resource initialization
|
# This info is also later picked-up by the 'permission' resource initialization
|
||||||
if label:
|
if label:
|
||||||
|
@ -1512,119 +1521,6 @@ def app_setting(app, key, value=None, delete=False):
|
||||||
"""
|
"""
|
||||||
app_settings = _get_app_settings(app) or {}
|
app_settings = _get_app_settings(app) or {}
|
||||||
|
|
||||||
#
|
|
||||||
# Legacy permission setting management
|
|
||||||
# (unprotected, protected, skipped_uri/regex)
|
|
||||||
#
|
|
||||||
|
|
||||||
is_legacy_permission_setting = any(
|
|
||||||
key.startswith(word + "_") for word in ["unprotected", "protected", "skipped"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_legacy_permission_setting:
|
|
||||||
from yunohost.permission import (
|
|
||||||
user_permission_list,
|
|
||||||
user_permission_update,
|
|
||||||
permission_create,
|
|
||||||
permission_delete,
|
|
||||||
permission_url,
|
|
||||||
)
|
|
||||||
|
|
||||||
permissions = user_permission_list(full=True, apps=[app])["permissions"]
|
|
||||||
key_ = key.split("_")[0]
|
|
||||||
permission_name = f"{app}.legacy_{key_}_uris"
|
|
||||||
permission = permissions.get(permission_name)
|
|
||||||
|
|
||||||
# GET
|
|
||||||
if value is None and not delete:
|
|
||||||
return (
|
|
||||||
",".join(permission.get("uris", []) + permission["additional_urls"])
|
|
||||||
if permission
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# DELETE
|
|
||||||
if delete:
|
|
||||||
# If 'is_public' setting still exists, we interpret this as
|
|
||||||
# coming from a legacy app (because new apps shouldn't manage the
|
|
||||||
# is_public state themselves anymore...)
|
|
||||||
#
|
|
||||||
# In that case, we interpret the request for "deleting
|
|
||||||
# unprotected/skipped" setting as willing to make the app
|
|
||||||
# private
|
|
||||||
if (
|
|
||||||
"is_public" in app_settings
|
|
||||||
and "visitors" in permissions[app + ".main"]["allowed"]
|
|
||||||
):
|
|
||||||
if key.startswith("unprotected_") or key.startswith("skipped_"):
|
|
||||||
user_permission_update(app + ".main", remove="visitors")
|
|
||||||
|
|
||||||
if permission:
|
|
||||||
permission_delete(permission_name)
|
|
||||||
|
|
||||||
# SET
|
|
||||||
else:
|
|
||||||
urls = value
|
|
||||||
# If the request is about the root of the app (/), ( = the vast majority of cases)
|
|
||||||
# we interpret this as a change for the main permission
|
|
||||||
# (i.e. allowing/disallowing visitors)
|
|
||||||
if urls == "/":
|
|
||||||
if key.startswith("unprotected_") or key.startswith("skipped_"):
|
|
||||||
permission_url(app + ".main", url="/", sync_perm=False)
|
|
||||||
user_permission_update(app + ".main", add="visitors")
|
|
||||||
else:
|
|
||||||
user_permission_update(app + ".main", remove="visitors")
|
|
||||||
else:
|
|
||||||
urls = urls.split(",")
|
|
||||||
if key.endswith("_regex"):
|
|
||||||
urls = ["re:" + url for url in urls]
|
|
||||||
|
|
||||||
if permission:
|
|
||||||
# In case of new regex, save the urls, to add a new time in the additional_urls
|
|
||||||
# In case of new urls, we do the same thing but inversed
|
|
||||||
if key.endswith("_regex"):
|
|
||||||
# List of urls to save
|
|
||||||
current_urls_or_regex = [
|
|
||||||
url
|
|
||||||
for url in permission["additional_urls"]
|
|
||||||
if not url.startswith("re:")
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
# List of regex to save
|
|
||||||
current_urls_or_regex = [
|
|
||||||
url
|
|
||||||
for url in permission["additional_urls"]
|
|
||||||
if url.startswith("re:")
|
|
||||||
]
|
|
||||||
|
|
||||||
new_urls = urls + current_urls_or_regex
|
|
||||||
# We need to clear urls because in the old setting the new setting override the old one and dont just add some urls
|
|
||||||
permission_url(permission_name, clear_urls=True, sync_perm=False)
|
|
||||||
permission_url(permission_name, add_url=new_urls)
|
|
||||||
else:
|
|
||||||
from yunohost.utils.legacy import legacy_permission_label
|
|
||||||
|
|
||||||
# Let's create a "special" permission for the legacy settings
|
|
||||||
permission_create(
|
|
||||||
permission=permission_name,
|
|
||||||
# FIXME find a way to limit to only the user allowed to the main permission
|
|
||||||
allowed=["all_users"]
|
|
||||||
if key.startswith("protected_")
|
|
||||||
else ["all_users", "visitors"],
|
|
||||||
url=None,
|
|
||||||
additional_urls=urls,
|
|
||||||
auth_header=not key.startswith("skipped_"),
|
|
||||||
label=legacy_permission_label(app, key.split("_")[0]),
|
|
||||||
show_tile=False,
|
|
||||||
protected=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
#
|
|
||||||
# Regular setting management
|
|
||||||
#
|
|
||||||
|
|
||||||
# GET
|
# GET
|
||||||
if value is None and not delete:
|
if value is None and not delete:
|
||||||
return app_settings.get(key, None)
|
return app_settings.get(key, None)
|
||||||
|
@ -1639,8 +1535,6 @@ def app_setting(app, key, value=None, delete=False):
|
||||||
|
|
||||||
# SET
|
# SET
|
||||||
else:
|
else:
|
||||||
if key in ["redirected_urls", "redirected_regex"]:
|
|
||||||
value = yaml.safe_load(value)
|
|
||||||
app_settings[key] = value
|
app_settings[key] = value
|
||||||
|
|
||||||
_set_app_settings(app, app_settings)
|
_set_app_settings(app, app_settings)
|
||||||
|
@ -1989,20 +1883,6 @@ def _get_app_settings(app):
|
||||||
logger.error(m18n.n("app_not_correctly_installed", app=app))
|
logger.error(m18n.n("app_not_correctly_installed", app=app))
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Stupid fix for legacy bullshit
|
|
||||||
# In the past, some setups did not have proper normalization for app domain/path
|
|
||||||
# Meaning some setups (as of January 2021) still have path=/foobar/ (with a trailing slash)
|
|
||||||
# resulting in stupid issue unless apps using ynh_app_normalize_path_stuff
|
|
||||||
# So we yolofix the settings if such an issue is found >_>
|
|
||||||
# A simple call to `yunohost app list` (which happens quite often) should be enough
|
|
||||||
# to migrate all app settings ... so this can probably be removed once we're past Bullseye...
|
|
||||||
if settings.get("path") != "/" and (
|
|
||||||
settings.get("path", "").endswith("/")
|
|
||||||
or not settings.get("path", "/").startswith("/")
|
|
||||||
):
|
|
||||||
settings["path"] = "/" + settings["path"].strip("/")
|
|
||||||
_set_app_settings(app, settings)
|
|
||||||
|
|
||||||
# Make the app id available as $app too
|
# Make the app id available as $app too
|
||||||
settings["app"] = app
|
settings["app"] = app
|
||||||
|
|
||||||
|
@ -2026,6 +1906,20 @@ def _set_app_settings(app, settings):
|
||||||
yaml.safe_dump(settings, f, default_flow_style=False)
|
yaml.safe_dump(settings, f, default_flow_style=False)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_app_version(v):
|
||||||
|
|
||||||
|
if v == "?":
|
||||||
|
return (0,0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if "~" in v:
|
||||||
|
return (version.parse(v.split("~")[0]), int(v.split("~")[1].replace("ynh", "")))
|
||||||
|
else:
|
||||||
|
return (version.parse(v), 0)
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError(f"Failed to parse app version '{v}' : {e}", raw_msg=True)
|
||||||
|
|
||||||
|
|
||||||
def _get_manifest_of_app(path):
|
def _get_manifest_of_app(path):
|
||||||
"Get app manifest stored in json or in toml"
|
"Get app manifest stored in json or in toml"
|
||||||
|
|
||||||
|
@ -2223,6 +2117,13 @@ def _parse_app_doc_and_notifications(path):
|
||||||
|
|
||||||
|
|
||||||
def _hydrate_app_template(template, data):
|
def _hydrate_app_template(template, data):
|
||||||
|
|
||||||
|
# Apply jinja for stuff like {% if .. %} blocks,
|
||||||
|
# but only if there's indeed an if block (to try to reduce overhead or idk)
|
||||||
|
if "{%" in template:
|
||||||
|
from jinja2 import Template
|
||||||
|
template = Template(template).render(**data)
|
||||||
|
|
||||||
stuff_to_replace = set(re.findall(r"__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__", template))
|
stuff_to_replace = set(re.findall(r"__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__", template))
|
||||||
|
|
||||||
for stuff in stuff_to_replace:
|
for stuff in stuff_to_replace:
|
||||||
|
@ -2231,7 +2132,7 @@ def _hydrate_app_template(template, data):
|
||||||
if varname in data:
|
if varname in data:
|
||||||
template = template.replace(stuff, str(data[varname]))
|
template = template.replace(stuff, str(data[varname]))
|
||||||
|
|
||||||
return template
|
return template.strip()
|
||||||
|
|
||||||
|
|
||||||
def _convert_v1_manifest_to_v2(manifest):
|
def _convert_v1_manifest_to_v2(manifest):
|
||||||
|
@ -2905,6 +2806,7 @@ def _make_environment_for_app_script(
|
||||||
app_id, app_instance_nb = _parse_app_instance_name(app)
|
app_id, app_instance_nb = _parse_app_instance_name(app)
|
||||||
|
|
||||||
env_dict = {
|
env_dict = {
|
||||||
|
"YNH_DEFAULT_PHP_VERSION": "8.2",
|
||||||
"YNH_APP_ID": app_id,
|
"YNH_APP_ID": app_id,
|
||||||
"YNH_APP_INSTANCE_NAME": app,
|
"YNH_APP_INSTANCE_NAME": app,
|
||||||
"YNH_APP_INSTANCE_NUMBER": str(app_instance_nb),
|
"YNH_APP_INSTANCE_NUMBER": str(app_instance_nb),
|
||||||
|
@ -3043,10 +2945,10 @@ def _assert_system_is_sane_for_app(manifest, when):
|
||||||
|
|
||||||
services = manifest.get("services", [])
|
services = manifest.get("services", [])
|
||||||
|
|
||||||
# Some apps use php-fpm, php5-fpm or php7.x-fpm which is now php7.4-fpm
|
# Some apps use php-fpm, php5-fpm or php7.x-fpm which is now php8.2-fpm
|
||||||
def replace_alias(service):
|
def replace_alias(service):
|
||||||
if service in ["php-fpm", "php5-fpm", "php7.0-fpm", "php7.3-fpm"]:
|
if service in ["php-fpm", "php5-fpm", "php7.0-fpm", "php7.3-fpm", "php7.4-fpm"]:
|
||||||
return "php7.4-fpm"
|
return "php8.2-fpm"
|
||||||
else:
|
else:
|
||||||
return service
|
return service
|
||||||
|
|
||||||
|
@ -3055,7 +2957,7 @@ def _assert_system_is_sane_for_app(manifest, when):
|
||||||
# We only check those, mostly to ignore "custom" services
|
# We only check those, mostly to ignore "custom" services
|
||||||
# (added by apps) and because those are the most popular
|
# (added by apps) and because those are the most popular
|
||||||
# services
|
# services
|
||||||
service_filter = ["nginx", "php7.4-fpm", "mysql", "postfix"]
|
service_filter = ["nginx", "php8.2-fpm", "mysql", "postfix"]
|
||||||
services = [str(s) for s in services if s in service_filter]
|
services = [str(s) for s in services if s in service_filter]
|
||||||
|
|
||||||
if "nginx" not in services:
|
if "nginx" not in services:
|
||||||
|
@ -3131,14 +3033,9 @@ def _notification_is_dismissed(name, settings):
|
||||||
def _filter_and_hydrate_notifications(notifications, current_version=None, data={}):
|
def _filter_and_hydrate_notifications(notifications, current_version=None, data={}):
|
||||||
def is_version_more_recent_than_current_version(name, current_version):
|
def is_version_more_recent_than_current_version(name, current_version):
|
||||||
current_version = str(current_version)
|
current_version = str(current_version)
|
||||||
# Boring code to handle the fact that "0.1 < 9999~ynh1" is False
|
return _parse_app_version(name) > _parse_app_version(current_version)
|
||||||
|
|
||||||
if "~" in name:
|
out = {
|
||||||
return version.parse(name) > version.parse(current_version)
|
|
||||||
else:
|
|
||||||
return version.parse(name) > version.parse(current_version.split("~")[0])
|
|
||||||
|
|
||||||
return {
|
|
||||||
# Should we render the markdown maybe? idk
|
# Should we render the markdown maybe? idk
|
||||||
name: _hydrate_app_template(_value_for_locale(content_per_lang), data)
|
name: _hydrate_app_template(_value_for_locale(content_per_lang), data)
|
||||||
for name, content_per_lang in notifications.items()
|
for name, content_per_lang in notifications.items()
|
||||||
|
@ -3147,6 +3044,9 @@ def _filter_and_hydrate_notifications(notifications, current_version=None, data=
|
||||||
or is_version_more_recent_than_current_version(name, current_version)
|
or is_version_more_recent_than_current_version(name, current_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Filter out empty notifications (notifications may be empty because of if blocks)
|
||||||
|
return {name:content for name, content in out.items() if content and content.strip()}
|
||||||
|
|
||||||
|
|
||||||
def _display_notifications(notifications, force=False):
|
def _display_notifications(notifications, force=False):
|
||||||
if not notifications:
|
if not notifications:
|
||||||
|
@ -3223,7 +3123,7 @@ def regen_mail_app_user_config_for_dovecot_and_postfix(only=None):
|
||||||
if dovecot:
|
if dovecot:
|
||||||
hashed_password = _hash_user_password(settings["mail_pwd"])
|
hashed_password = _hash_user_password(settings["mail_pwd"])
|
||||||
dovecot_passwd.append(
|
dovecot_passwd.append(
|
||||||
f"{app}:{hashed_password}::::::allow_nets=127.0.0.1/24"
|
f"{app}:{hashed_password}::::::allow_nets=::1,127.0.0.1/24,local"
|
||||||
)
|
)
|
||||||
if postfix:
|
if postfix:
|
||||||
mail_user = settings.get("mail_user", app)
|
mail_user = settings.get("mail_user", app)
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import hashlib
|
import hashlib
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.network import download_json
|
from moulinette.utils.network import download_json
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
read_json,
|
read_json,
|
||||||
|
@ -34,7 +34,7 @@ from moulinette.utils.filesystem import (
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.app_catalog")
|
logger = getLogger("yunohost.app_catalog")
|
||||||
|
|
||||||
APPS_CATALOG_CACHE = "/var/cache/yunohost/repo"
|
APPS_CATALOG_CACHE = "/var/cache/yunohost/repo"
|
||||||
APPS_CATALOG_LOGOS = "/usr/share/yunohost/applogos"
|
APPS_CATALOG_LOGOS = "/usr/share/yunohost/applogos"
|
||||||
|
|
|
@ -30,10 +30,10 @@ from glob import glob
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.text import random_ascii
|
from moulinette.utils.text import random_ascii
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
read_file,
|
read_file,
|
||||||
mkdir,
|
mkdir,
|
||||||
|
@ -84,7 +84,7 @@ APP_MARGIN_SPACE_SIZE = 100 # In MB
|
||||||
CONF_MARGIN_SPACE_SIZE = 10 # IN MB
|
CONF_MARGIN_SPACE_SIZE = 10 # IN MB
|
||||||
POSTINSTALL_ESTIMATE_SPACE_SIZE = 5 # In MB
|
POSTINSTALL_ESTIMATE_SPACE_SIZE = 5 # In MB
|
||||||
MB_ALLOWED_TO_ORGANIZE = 10
|
MB_ALLOWED_TO_ORGANIZE = 10
|
||||||
logger = getActionLogger("yunohost.backup")
|
logger = getLogger("yunohost.backup")
|
||||||
|
|
||||||
|
|
||||||
class BackupRestoreTargetsManager:
|
class BackupRestoreTargetsManager:
|
||||||
|
@ -1204,7 +1204,7 @@ class RestoreManager:
|
||||||
|
|
||||||
def _patch_legacy_php_versions_in_csv_file(self):
|
def _patch_legacy_php_versions_in_csv_file(self):
|
||||||
"""
|
"""
|
||||||
Apply dirty patch to redirect php5 and php7.0 files to php7.4
|
Apply dirty patch to redirect php5 and php7.x files to php8.2
|
||||||
"""
|
"""
|
||||||
from yunohost.utils.legacy import LEGACY_PHP_VERSION_REPLACEMENTS
|
from yunohost.utils.legacy import LEGACY_PHP_VERSION_REPLACEMENTS
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,10 @@ import sys
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
from logging import getLogger
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import read_file, chown, chmod
|
from moulinette.utils.filesystem import read_file, chown, chmod
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ from yunohost.service import _run_service_command
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.certmanager")
|
logger = getLogger("yunohost.certmanager")
|
||||||
|
|
||||||
CERT_FOLDER = "/etc/yunohost/certs/"
|
CERT_FOLDER = "/etc/yunohost/certs/"
|
||||||
TMP_FOLDER = "/var/www/.well-known/acme-challenge-private/"
|
TMP_FOLDER = "/var/www/.well-known/acme-challenge-private/"
|
||||||
|
|
|
@ -215,6 +215,11 @@ class MyDiagnoser(Diagnoser):
|
||||||
for part in current
|
for part in current
|
||||||
if not part.startswith("ip4:") and not part.startswith("ip6:")
|
if not part.startswith("ip4:") and not part.startswith("ip6:")
|
||||||
}
|
}
|
||||||
|
if "v=DMARC1" in r["value"]:
|
||||||
|
for param in current:
|
||||||
|
key, value = param.split("=")
|
||||||
|
if key == "p":
|
||||||
|
return value in ["none", "quarantine", "reject"]
|
||||||
return expected == current
|
return expected == current
|
||||||
elif r["type"] == "MX":
|
elif r["type"] == "MX":
|
||||||
# For MX, we want to ignore the priority
|
# For MX, we want to ignore the priority
|
||||||
|
|
|
@ -43,7 +43,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
dependencies: List[str] = ["ip"]
|
dependencies: List[str] = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.ehlo_domain = _get_maindomain()
|
self.ehlo_domain = _get_maindomain().lower()
|
||||||
self.mail_domains = domain_list()["domains"]
|
self.mail_domains = domain_list()["domains"]
|
||||||
self.ipversions, self.ips = self.get_ips_checked()
|
self.ipversions, self.ips = self.get_ips_checked()
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
details=[summary + "_details"],
|
details=[summary + "_details"],
|
||||||
)
|
)
|
||||||
elif r["helo"] != self.ehlo_domain:
|
elif r["helo"].lower() != self.ehlo_domain:
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "mail_ehlo", "ipversion": ipversion},
|
meta={"test": "mail_ehlo", "ipversion": ipversion},
|
||||||
data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain},
|
data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain},
|
||||||
|
@ -185,7 +185,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
rdns_domain = ""
|
rdns_domain = ""
|
||||||
if len(value) > 0:
|
if len(value) > 0:
|
||||||
rdns_domain = value[0][:-1] if value[0].endswith(".") else value[0]
|
rdns_domain = value[0][:-1] if value[0].endswith(".") else value[0]
|
||||||
if rdns_domain != self.ehlo_domain:
|
if rdns_domain.lower() != self.ehlo_domain:
|
||||||
details = [
|
details = [
|
||||||
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details"
|
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details"
|
||||||
] + details
|
] + details
|
||||||
|
@ -194,7 +194,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
data={
|
data={
|
||||||
"ip": ip,
|
"ip": ip,
|
||||||
"ehlo_domain": self.ehlo_domain,
|
"ehlo_domain": self.ehlo_domain,
|
||||||
"rdns_domain": rdns_domain,
|
"rdns_domain": rdns_domain.lower(),
|
||||||
},
|
},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary="diagnosis_mail_fcrdns_different_from_ehlo_domain",
|
summary="diagnosis_mail_fcrdns_different_from_ehlo_domain",
|
||||||
|
|
|
@ -21,6 +21,7 @@ import os
|
||||||
import time
|
import time
|
||||||
import glob
|
import glob
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from moulinette.utils import log
|
from moulinette.utils import log
|
||||||
|
@ -33,7 +34,7 @@ from moulinette.utils.filesystem import (
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.diagnosis")
|
logger = getLogger("yunohost.diagnosis")
|
||||||
|
|
||||||
DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/"
|
DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/"
|
||||||
DIAGNOSIS_CONFIG_FILE = "/etc/yunohost/diagnosis.yml"
|
DIAGNOSIS_CONFIG_FILE = "/etc/yunohost/diagnosis.yml"
|
||||||
|
|
|
@ -19,12 +19,11 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
from logging import getLogger
|
||||||
from difflib import SequenceMatcher
|
from difflib import SequenceMatcher
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import read_file, write_to_file, read_toml, mkdir
|
from moulinette.utils.filesystem import read_file, write_to_file, read_toml, mkdir
|
||||||
|
|
||||||
from yunohost.domain import (
|
from yunohost.domain import (
|
||||||
|
@ -42,7 +41,7 @@ from yunohost.settings import settings_get
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.hook import hook_callback
|
from yunohost.hook import hook_callback
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.domain")
|
logger = getLogger("yunohost.domain")
|
||||||
|
|
||||||
DOMAIN_REGISTRAR_LIST_PATH = "/usr/share/yunohost/registrar_list.toml"
|
DOMAIN_REGISTRAR_LIST_PATH = "/usr/share/yunohost/registrar_list.toml"
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ import os
|
||||||
import time
|
import time
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml, rm
|
from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml, rm
|
||||||
|
|
||||||
from yunohost.app import (
|
from yunohost.app import (
|
||||||
|
@ -39,7 +39,7 @@ from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.dns import is_yunohost_dyndns_domain
|
from yunohost.utils.dns import is_yunohost_dyndns_domain
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.domain")
|
logger = getLogger("yunohost.domain")
|
||||||
|
|
||||||
DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains"
|
DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains"
|
||||||
|
|
||||||
|
@ -175,11 +175,12 @@ def domain_info(domain):
|
||||||
|
|
||||||
from yunohost.app import app_info
|
from yunohost.app import app_info
|
||||||
from yunohost.dns import _get_registar_settings
|
from yunohost.dns import _get_registar_settings
|
||||||
|
from yunohost.certificate import certificate_status
|
||||||
|
|
||||||
_assert_domain_exists(domain)
|
_assert_domain_exists(domain)
|
||||||
|
|
||||||
registrar, _ = _get_registar_settings(domain)
|
registrar, _ = _get_registar_settings(domain)
|
||||||
certificate = domain_cert_status([domain], full=True)["certificates"][domain]
|
certificate = certificate_status([domain], full=True)["certificates"][domain]
|
||||||
|
|
||||||
apps = []
|
apps = []
|
||||||
for app in _installed_apps():
|
for app in _installed_apps():
|
||||||
|
@ -865,10 +866,6 @@ def domain_cert_renew(domain_list, force=False, no_checks=False, email=False):
|
||||||
return certificate_renew(domain_list, force, no_checks, email)
|
return certificate_renew(domain_list, force, no_checks, email)
|
||||||
|
|
||||||
|
|
||||||
def domain_dns_conf(domain):
|
|
||||||
return domain_dns_suggest(domain)
|
|
||||||
|
|
||||||
|
|
||||||
def domain_dns_suggest(domain):
|
def domain_dns_suggest(domain):
|
||||||
from yunohost.dns import domain_dns_suggest
|
from yunohost.dns import domain_dns_suggest
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ import glob
|
||||||
import base64
|
import base64
|
||||||
import subprocess
|
import subprocess
|
||||||
import hashlib
|
import hashlib
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import write_to_file, rm, chown, chmod
|
from moulinette.utils.filesystem import write_to_file, rm, chown, chmod
|
||||||
from moulinette.utils.network import download_json
|
from moulinette.utils.network import download_json
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ from yunohost.utils.dns import dig, is_yunohost_dyndns_domain
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.dyndns")
|
logger = getLogger("yunohost.dyndns")
|
||||||
|
|
||||||
DYNDNS_PROVIDER = "dyndns.yunohost.org"
|
DYNDNS_PROVIDER = "dyndns.yunohost.org"
|
||||||
DYNDNS_DNS_AUTH = ["ns0.yunohost.org", "ns1.yunohost.org"]
|
DYNDNS_DNS_AUTH = ["ns0.yunohost.org", "ns1.yunohost.org"]
|
||||||
|
|
|
@ -19,16 +19,16 @@
|
||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
import miniupnpc
|
import miniupnpc
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils import process
|
from moulinette.utils import process
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
|
|
||||||
FIREWALL_FILE = "/etc/yunohost/firewall.yml"
|
FIREWALL_FILE = "/etc/yunohost/firewall.yml"
|
||||||
UPNP_CRON_JOB = "/etc/cron.d/yunohost-firewall-upnp"
|
UPNP_CRON_JOB = "/etc/cron.d/yunohost-firewall-upnp"
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.firewall")
|
logger = getLogger("yunohost.firewall")
|
||||||
|
|
||||||
|
|
||||||
def firewall_allow(
|
def firewall_allow(
|
||||||
|
@ -402,7 +402,13 @@ def firewall_upnp(action="status", no_refresh=False):
|
||||||
|
|
||||||
# Discover UPnP device(s)
|
# Discover UPnP device(s)
|
||||||
logger.debug("discovering UPnP devices...")
|
logger.debug("discovering UPnP devices...")
|
||||||
nb_dev = upnpc.discover()
|
try:
|
||||||
|
nb_dev = upnpc.discover()
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Failed to find any UPnP device on the network")
|
||||||
|
nb_dev = -1
|
||||||
|
enabled = False
|
||||||
|
|
||||||
logger.debug("found %d UPnP device(s)", int(nb_dev))
|
logger.debug("found %d UPnP device(s)", int(nb_dev))
|
||||||
if nb_dev < 1:
|
if nb_dev < 1:
|
||||||
logger.error(m18n.n("upnp_dev_not_found"))
|
logger.error(m18n.n("upnp_dev_not_found"))
|
||||||
|
|
|
@ -23,16 +23,16 @@ import tempfile
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from glob import iglob
|
from glob import iglob
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils import log
|
|
||||||
from moulinette.utils.filesystem import read_yaml, cp
|
from moulinette.utils.filesystem import read_yaml, cp
|
||||||
|
|
||||||
HOOK_FOLDER = "/usr/share/yunohost/hooks/"
|
HOOK_FOLDER = "/usr/share/yunohost/hooks/"
|
||||||
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
|
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.hook")
|
logger = getLogger("yunohost.hook")
|
||||||
|
|
||||||
|
|
||||||
def hook_add(app, file):
|
def hook_add(app, file):
|
||||||
|
@ -359,6 +359,7 @@ def hook_exec(
|
||||||
r"Removing obsolete dictionary files",
|
r"Removing obsolete dictionary files",
|
||||||
r"Creating new PostgreSQL cluster",
|
r"Creating new PostgreSQL cluster",
|
||||||
r"/usr/lib/postgresql/13/bin/initdb",
|
r"/usr/lib/postgresql/13/bin/initdb",
|
||||||
|
r"/usr/lib/postgresql/15/bin/initdb",
|
||||||
r"The files belonging to this database system will be owned by user",
|
r"The files belonging to this database system will be owned by user",
|
||||||
r"This user must also own the server process.",
|
r"This user must also own the server process.",
|
||||||
r"The database cluster will be initialized with locale",
|
r"The database cluster will be initialized with locale",
|
||||||
|
@ -366,6 +367,7 @@ def hook_exec(
|
||||||
r"The default text search configuration will be set to",
|
r"The default text search configuration will be set to",
|
||||||
r"Data page checksums are disabled.",
|
r"Data page checksums are disabled.",
|
||||||
r"fixing permissions on existing directory /var/lib/postgresql/13/main ... ok",
|
r"fixing permissions on existing directory /var/lib/postgresql/13/main ... ok",
|
||||||
|
r"fixing permissions on existing directory /var/lib/postgresql/15/main ... ok",
|
||||||
r"creating subdirectories \.\.\. ok",
|
r"creating subdirectories \.\.\. ok",
|
||||||
r"selecting dynamic .* \.\.\. ",
|
r"selecting dynamic .* \.\.\. ",
|
||||||
r"selecting default .* \.\.\. ",
|
r"selecting default .* \.\.\. ",
|
||||||
|
|
|
@ -32,10 +32,9 @@ from moulinette import m18n, Moulinette
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.system import get_ynh_package_version
|
from yunohost.utils.system import get_ynh_package_version
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import read_file, read_yaml
|
from moulinette.utils.filesystem import read_file, read_yaml
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.log")
|
logger = getLogger("yunohost.log")
|
||||||
|
|
||||||
CATEGORIES_PATH = "/var/log/yunohost/categories/"
|
CATEGORIES_PATH = "/var/log/yunohost/categories/"
|
||||||
OPERATIONS_PATH = "/var/log/yunohost/categories/operation/"
|
OPERATIONS_PATH = "/var/log/yunohost/categories/operation/"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.process import check_output, call_async_output
|
from moulinette.utils.process import check_output, call_async_output
|
||||||
from moulinette.utils.filesystem import read_file, rm, write_to_file
|
from moulinette.utils.filesystem import read_file, rm, write_to_file
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ from yunohost.utils.system import (
|
||||||
)
|
)
|
||||||
from yunohost.service import _get_services, _save_services
|
from yunohost.service import _get_services, _save_services
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
N_CURRENT_DEBIAN = 10
|
N_CURRENT_DEBIAN = 10
|
||||||
N_CURRENT_YUNOHOST = 4
|
N_CURRENT_YUNOHOST = 4
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
from shutil import copy2
|
from shutil import copy2
|
||||||
|
from logging import getLogger
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
|
|
||||||
from yunohost.app import _is_installed
|
from yunohost.app import _is_installed
|
||||||
from yunohost.utils.legacy import _patch_legacy_php_versions_in_settings
|
from yunohost.utils.legacy import _patch_legacy_php_versions_in_settings
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.service import _run_service_command
|
from yunohost.service import _run_service_command
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
OLDPHP_POOLS = "/etc/php/7.3/fpm/pool.d"
|
OLDPHP_POOLS = "/etc/php/7.3/fpm/pool.d"
|
||||||
NEWPHP_POOLS = "/etc/php/7.4/fpm/pool.d"
|
NEWPHP_POOLS = "/etc/php/7.4/fpm/pool.d"
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.utils.system import free_space_in_directory, space_used_by_directory
|
from yunohost.utils.system import free_space_in_directory, space_used_by_directory
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
|
|
||||||
class MyMigration(Migration):
|
class MyMigration(Migration):
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import os
|
import os
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.process import call_async_output
|
from moulinette.utils.process import call_async_output
|
||||||
|
|
||||||
from yunohost.tools import Migration, tools_migrations_state
|
from yunohost.tools import Migration, tools_migrations_state
|
||||||
from moulinette.utils.filesystem import rm
|
from moulinette.utils.filesystem import rm
|
||||||
|
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
VENV_REQUIREMENTS_SUFFIX = ".requirements_backup_for_bullseye_upgrade.txt"
|
VENV_REQUIREMENTS_SUFFIX = ".requirements_backup_for_bullseye_upgrade.txt"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import os
|
import os
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import read_json, write_to_yaml
|
from moulinette.utils.filesystem import read_json, write_to_yaml
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
||||||
OLD_SETTINGS_PATH = "/etc/yunohost/settings.json"
|
OLD_SETTINGS_PATH = "/etc/yunohost/settings.json"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from moulinette.utils.log import getActionLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.migration")
|
logger = getLogger("yunohost.migration")
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# Tools used also for restoration
|
# Tools used also for restoration
|
||||||
|
|
|
@ -20,13 +20,13 @@ import re
|
||||||
import copy
|
import copy
|
||||||
import grp
|
import grp
|
||||||
import random
|
import random
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.user")
|
logger = getLogger("yunohost.user")
|
||||||
|
|
||||||
SYSTEM_PERMS = ["mail", "xmpp", "sftp", "ssh"]
|
SYSTEM_PERMS = ["mail", "xmpp", "sftp", "ssh"]
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,12 @@ import os
|
||||||
import yaml
|
import yaml
|
||||||
import shutil
|
import shutil
|
||||||
import hashlib
|
import hashlib
|
||||||
|
from logging import getLogger
|
||||||
from difflib import unified_diff
|
from difflib import unified_diff
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils import log, filesystem
|
from moulinette.utils.filesystem import mkdir
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
@ -37,7 +37,7 @@ BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, "backup")
|
||||||
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, "pending")
|
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, "pending")
|
||||||
REGEN_CONF_FILE = "/etc/yunohost/regenconf.yml"
|
REGEN_CONF_FILE = "/etc/yunohost/regenconf.yml"
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.regenconf")
|
logger = getLogger("yunohost.regenconf")
|
||||||
|
|
||||||
|
|
||||||
# FIXME : those ain't just services anymore ... what are we supposed to do with this ...
|
# FIXME : those ain't just services anymore ... what are we supposed to do with this ...
|
||||||
|
@ -102,7 +102,7 @@ def regen_conf(
|
||||||
for name in names:
|
for name in names:
|
||||||
shutil.rmtree(os.path.join(PENDING_CONF_DIR, name), ignore_errors=True)
|
shutil.rmtree(os.path.join(PENDING_CONF_DIR, name), ignore_errors=True)
|
||||||
else:
|
else:
|
||||||
filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
|
mkdir(PENDING_CONF_DIR, 0o755, True)
|
||||||
|
|
||||||
# Execute hooks for pre-regen
|
# Execute hooks for pre-regen
|
||||||
# element 2 and 3 with empty string is because of legacy...
|
# element 2 and 3 with empty string is because of legacy...
|
||||||
|
@ -111,7 +111,7 @@ def regen_conf(
|
||||||
def _pre_call(name, priority, path, args):
|
def _pre_call(name, priority, path, args):
|
||||||
# create the pending conf directory for the category
|
# create the pending conf directory for the category
|
||||||
category_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
category_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
||||||
filesystem.mkdir(category_pending_path, 0o755, True, uid="root")
|
mkdir(category_pending_path, 0o755, True, uid="root")
|
||||||
|
|
||||||
# return the arguments to pass to the script
|
# return the arguments to pass to the script
|
||||||
return pre_args + [
|
return pre_args + [
|
||||||
|
@ -622,7 +622,7 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
|
||||||
backup_dir = os.path.dirname(backup_path)
|
backup_dir = os.path.dirname(backup_path)
|
||||||
|
|
||||||
if not os.path.isdir(backup_dir):
|
if not os.path.isdir(backup_dir):
|
||||||
filesystem.mkdir(backup_dir, 0o755, True)
|
mkdir(backup_dir, 0o755, True)
|
||||||
|
|
||||||
shutil.copy2(system_conf, backup_path)
|
shutil.copy2(system_conf, backup_path)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
@ -637,7 +637,7 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
|
||||||
system_dir = os.path.dirname(system_conf)
|
system_dir = os.path.dirname(system_conf)
|
||||||
|
|
||||||
if not os.path.isdir(system_dir):
|
if not os.path.isdir(system_dir):
|
||||||
filesystem.mkdir(system_dir, 0o755, True)
|
mkdir(system_dir, 0o755, True)
|
||||||
|
|
||||||
shutil.copyfile(new_conf, system_conf)
|
shutil.copyfile(new_conf, system_conf)
|
||||||
logger.debug(m18n.n("regenconf_file_updated", conf=system_conf))
|
logger.debug(m18n.n("regenconf_file_updated", conf=system_conf))
|
||||||
|
|
|
@ -21,14 +21,13 @@ import os
|
||||||
import time
|
import time
|
||||||
import yaml
|
import yaml
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from logging import getLogger
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
read_file,
|
read_file,
|
||||||
append_to_file,
|
append_to_file,
|
||||||
|
@ -42,7 +41,7 @@ MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
|
||||||
SERVICES_CONF = "/etc/yunohost/services.yml"
|
SERVICES_CONF = "/etc/yunohost/services.yml"
|
||||||
SERVICES_CONF_BASE = "/usr/share/yunohost/conf/yunohost/services.yml"
|
SERVICES_CONF_BASE = "/usr/share/yunohost/conf/yunohost/services.yml"
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.service")
|
logger = getLogger("yunohost.service")
|
||||||
|
|
||||||
|
|
||||||
def service_add(
|
def service_add(
|
||||||
|
|
|
@ -18,18 +18,18 @@
|
||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.configpanel import ConfigPanel
|
from yunohost.utils.configpanel import ConfigPanel
|
||||||
from yunohost.utils.form import BaseOption
|
from yunohost.utils.form import BaseOption
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.firewall import firewall_reload
|
from yunohost.firewall import firewall_reload
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.settings")
|
logger = getLogger("yunohost.settings")
|
||||||
|
|
||||||
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import moulinette
|
import moulinette
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
|
@ -23,11 +24,15 @@ def get_test_apps_dir():
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def message(mocker, key, **kwargs):
|
def message(key, **kwargs):
|
||||||
mocker.spy(m18n, "n")
|
m = Mock(wraps=m18n.n)
|
||||||
|
old_m18n = m18n.n
|
||||||
|
m18n.n = m
|
||||||
yield
|
yield
|
||||||
m18n.n.assert_any_call(key, **kwargs)
|
try:
|
||||||
|
m.assert_any_call(key, **kwargs)
|
||||||
|
finally:
|
||||||
|
m18n.n = old_m18n
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def raiseYunohostError(mocker, key, **kwargs):
|
def raiseYunohostError(mocker, key, **kwargs):
|
||||||
|
|
|
@ -5,6 +5,8 @@ import requests_mock
|
||||||
import glob
|
import glob
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from .conftest import message
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.filesystem import read_json, write_to_json, write_to_yaml
|
from moulinette.utils.filesystem import read_json, write_to_json, write_to_yaml
|
||||||
|
|
||||||
|
@ -258,13 +260,12 @@ def test_apps_catalog_load_with_conflicts_between_lists(mocker):
|
||||||
assert "bar" in app_dict.keys()
|
assert "bar" in app_dict.keys()
|
||||||
|
|
||||||
|
|
||||||
def test_apps_catalog_load_with_oudated_api_version(mocker):
|
def test_apps_catalog_load_with_outdated_api_version():
|
||||||
# Initialize ...
|
# Initialize ...
|
||||||
_initialize_apps_catalog_system()
|
_initialize_apps_catalog_system()
|
||||||
|
|
||||||
# Update
|
# Update
|
||||||
with requests_mock.Mocker() as m:
|
with requests_mock.Mocker() as m:
|
||||||
mocker.spy(m18n, "n")
|
|
||||||
m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG)
|
m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG)
|
||||||
_update_apps_catalog()
|
_update_apps_catalog()
|
||||||
|
|
||||||
|
@ -282,10 +283,8 @@ def test_apps_catalog_load_with_oudated_api_version(mocker):
|
||||||
with requests_mock.Mocker() as m:
|
with requests_mock.Mocker() as m:
|
||||||
# Mock the server response with a dummy apps catalog
|
# Mock the server response with a dummy apps catalog
|
||||||
m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG)
|
m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG)
|
||||||
|
with message("apps_catalog_update_success"):
|
||||||
mocker.spy(m18n, "n")
|
app_dict = _load_apps_catalog()["apps"]
|
||||||
app_dict = _load_apps_catalog()["apps"]
|
|
||||||
m18n.n.assert_any_call("apps_catalog_update_success")
|
|
||||||
|
|
||||||
assert "foo" in app_dict.keys()
|
assert "foo" in app_dict.keys()
|
||||||
assert "bar" in app_dict.keys()
|
assert "bar" in app_dict.keys()
|
||||||
|
|
|
@ -394,9 +394,9 @@ def test_legacy_app_install_private(secondary_domain):
|
||||||
assert app_is_not_installed(secondary_domain, "legacy_app")
|
assert app_is_not_installed(secondary_domain, "legacy_app")
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_app_install_unknown_domain(mocker):
|
def test_legacy_app_install_unknown_domain():
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_argument_invalid"):
|
with message("app_argument_invalid"):
|
||||||
install_legacy_app("whatever.nope", "/legacy")
|
install_legacy_app("whatever.nope", "/legacy")
|
||||||
|
|
||||||
assert app_is_not_installed("whatever.nope", "legacy_app")
|
assert app_is_not_installed("whatever.nope", "legacy_app")
|
||||||
|
@ -423,12 +423,12 @@ def test_legacy_app_install_multiple_instances(secondary_domain):
|
||||||
assert app_is_not_installed(secondary_domain, "legacy_app__2")
|
assert app_is_not_installed(secondary_domain, "legacy_app__2")
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_app_install_path_unavailable(mocker, secondary_domain):
|
def test_legacy_app_install_path_unavailable(secondary_domain):
|
||||||
# These will be removed in teardown
|
# These will be removed in teardown
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_location_unavailable"):
|
with message("app_location_unavailable"):
|
||||||
install_legacy_app(secondary_domain, "/")
|
install_legacy_app(secondary_domain, "/")
|
||||||
|
|
||||||
assert app_is_installed(secondary_domain, "legacy_app")
|
assert app_is_installed(secondary_domain, "legacy_app")
|
||||||
|
@ -444,19 +444,19 @@ def test_legacy_app_install_with_nginx_down(mocker, secondary_domain):
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_app_failed_install(mocker, secondary_domain):
|
def test_legacy_app_failed_install(secondary_domain):
|
||||||
# This will conflict with the folder that the app
|
# This will conflict with the folder that the app
|
||||||
# attempts to create, making the install fail
|
# attempts to create, making the install fail
|
||||||
mkdir("/var/www/legacy_app/", 0o750)
|
mkdir("/var/www/legacy_app/", 0o750)
|
||||||
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_install_script_failed"):
|
with message("app_install_script_failed"):
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
|
|
||||||
assert app_is_not_installed(secondary_domain, "legacy_app")
|
assert app_is_not_installed(secondary_domain, "legacy_app")
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_app_failed_remove(mocker, secondary_domain):
|
def test_legacy_app_failed_remove(secondary_domain):
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
|
|
||||||
# The remove script runs with set -eu and attempt to remove this
|
# The remove script runs with set -eu and attempt to remove this
|
||||||
|
@ -488,52 +488,52 @@ def test_full_domain_app_with_conflicts(mocker, secondary_domain):
|
||||||
install_full_domain_app(secondary_domain)
|
install_full_domain_app(secondary_domain)
|
||||||
|
|
||||||
|
|
||||||
def test_systemfuckedup_during_app_install(mocker, secondary_domain):
|
def test_systemfuckedup_during_app_install(secondary_domain):
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_install_failed"):
|
with message("app_install_failed"):
|
||||||
with message(mocker, "app_action_broke_system"):
|
with message("app_action_broke_system"):
|
||||||
install_break_yo_system(secondary_domain, breakwhat="install")
|
install_break_yo_system(secondary_domain, breakwhat="install")
|
||||||
|
|
||||||
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
||||||
|
|
||||||
|
|
||||||
def test_systemfuckedup_during_app_remove(mocker, secondary_domain):
|
def test_systemfuckedup_during_app_remove(secondary_domain):
|
||||||
install_break_yo_system(secondary_domain, breakwhat="remove")
|
install_break_yo_system(secondary_domain, breakwhat="remove")
|
||||||
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_action_broke_system"):
|
with message("app_action_broke_system"):
|
||||||
with message(mocker, "app_removed"):
|
with message("app_removed"):
|
||||||
app_remove("break_yo_system")
|
app_remove("break_yo_system")
|
||||||
|
|
||||||
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
||||||
|
|
||||||
|
|
||||||
def test_systemfuckedup_during_app_install_and_remove(mocker, secondary_domain):
|
def test_systemfuckedup_during_app_install_and_remove(secondary_domain):
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_install_failed"):
|
with message("app_install_failed"):
|
||||||
with message(mocker, "app_action_broke_system"):
|
with message("app_action_broke_system"):
|
||||||
install_break_yo_system(secondary_domain, breakwhat="everything")
|
install_break_yo_system(secondary_domain, breakwhat="everything")
|
||||||
|
|
||||||
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
assert app_is_not_installed(secondary_domain, "break_yo_system")
|
||||||
|
|
||||||
|
|
||||||
def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain):
|
def test_systemfuckedup_during_app_upgrade(secondary_domain):
|
||||||
install_break_yo_system(secondary_domain, breakwhat="upgrade")
|
install_break_yo_system(secondary_domain, breakwhat="upgrade")
|
||||||
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_action_broke_system"):
|
with message("app_action_broke_system"):
|
||||||
app_upgrade(
|
app_upgrade(
|
||||||
"break_yo_system",
|
"break_yo_system",
|
||||||
file=os.path.join(get_test_apps_dir(), "break_yo_system_ynh"),
|
file=os.path.join(get_test_apps_dir(), "break_yo_system_ynh"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_failed_multiple_app_upgrade(mocker, secondary_domain):
|
def test_failed_multiple_app_upgrade(secondary_domain):
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
install_break_yo_system(secondary_domain, breakwhat="upgrade")
|
install_break_yo_system(secondary_domain, breakwhat="upgrade")
|
||||||
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
with message(mocker, "app_not_upgraded"):
|
with message("app_not_upgraded"):
|
||||||
app_upgrade(
|
app_upgrade(
|
||||||
["break_yo_system", "legacy_app"],
|
["break_yo_system", "legacy_app"],
|
||||||
file={
|
file={
|
||||||
|
|
|
@ -217,10 +217,6 @@ def test_normalize_permission_path_with_bad_regex():
|
||||||
)
|
)
|
||||||
|
|
||||||
# Full Regex
|
# Full Regex
|
||||||
with pytest.raises(YunohostError):
|
|
||||||
_validate_and_sanitize_permission_url(
|
|
||||||
"re:" + maindomain + "/yolo?+/", maindomain + "/path", "test_permission"
|
|
||||||
)
|
|
||||||
with pytest.raises(YunohostError):
|
with pytest.raises(YunohostError):
|
||||||
_validate_and_sanitize_permission_url(
|
_validate_and_sanitize_permission_url(
|
||||||
"re:" + maindomain + "/yolo[1-9]**/",
|
"re:" + maindomain + "/yolo[1-9]**/",
|
||||||
|
|
|
@ -49,8 +49,8 @@ def setup_function(function):
|
||||||
for m in function.__dict__.get("pytestmark", [])
|
for m in function.__dict__.get("pytestmark", [])
|
||||||
}
|
}
|
||||||
|
|
||||||
if "with_wordpress_archive_from_4p2" in markers:
|
if "with_wordpress_archive_from_11p2" in markers:
|
||||||
add_archive_wordpress_from_4p2()
|
add_archive_wordpress_from_11p2()
|
||||||
assert len(backup_list()["archives"]) == 1
|
assert len(backup_list()["archives"]) == 1
|
||||||
|
|
||||||
if "with_legacy_app_installed" in markers:
|
if "with_legacy_app_installed" in markers:
|
||||||
|
@ -72,8 +72,8 @@ def setup_function(function):
|
||||||
)
|
)
|
||||||
assert app_is_installed("backup_recommended_app")
|
assert app_is_installed("backup_recommended_app")
|
||||||
|
|
||||||
if "with_system_archive_from_4p2" in markers:
|
if "with_system_archive_from_11p2" in markers:
|
||||||
add_archive_system_from_4p2()
|
add_archive_system_from_11p2()
|
||||||
assert len(backup_list()["archives"]) == 1
|
assert len(backup_list()["archives"]) == 1
|
||||||
|
|
||||||
if "with_permission_app_installed" in markers:
|
if "with_permission_app_installed" in markers:
|
||||||
|
@ -148,7 +148,7 @@ def app_is_installed(app):
|
||||||
def backup_test_dependencies_are_met():
|
def backup_test_dependencies_are_met():
|
||||||
# Dummy test apps (or backup archives)
|
# Dummy test apps (or backup archives)
|
||||||
assert os.path.exists(
|
assert os.path.exists(
|
||||||
os.path.join(get_test_apps_dir(), "backup_wordpress_from_4p2")
|
os.path.join(get_test_apps_dir(), "backup_wordpress_from_11p2")
|
||||||
)
|
)
|
||||||
assert os.path.exists(os.path.join(get_test_apps_dir(), "legacy_app_ynh"))
|
assert os.path.exists(os.path.join(get_test_apps_dir(), "legacy_app_ynh"))
|
||||||
assert os.path.exists(
|
assert os.path.exists(
|
||||||
|
@ -211,23 +211,23 @@ def install_app(app, path, additionnal_args=""):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_archive_wordpress_from_4p2():
|
def add_archive_wordpress_from_11p2():
|
||||||
os.system("mkdir -p /home/yunohost.backup/archives")
|
os.system("mkdir -p /home/yunohost.backup/archives")
|
||||||
|
|
||||||
os.system(
|
os.system(
|
||||||
"cp "
|
"cp "
|
||||||
+ os.path.join(get_test_apps_dir(), "backup_wordpress_from_4p2/backup.tar")
|
+ os.path.join(get_test_apps_dir(), "backup_wordpress_from_11p2/backup.tar")
|
||||||
+ " /home/yunohost.backup/archives/backup_wordpress_from_4p2.tar"
|
+ " /home/yunohost.backup/archives/backup_wordpress_from_11p2.tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_archive_system_from_4p2():
|
def add_archive_system_from_11p2():
|
||||||
os.system("mkdir -p /home/yunohost.backup/archives")
|
os.system("mkdir -p /home/yunohost.backup/archives")
|
||||||
|
|
||||||
os.system(
|
os.system(
|
||||||
"cp "
|
"cp "
|
||||||
+ os.path.join(get_test_apps_dir(), "backup_system_from_4p2/backup.tar")
|
+ os.path.join(get_test_apps_dir(), "backup_system_from_11p2/backup.tar")
|
||||||
+ " /home/yunohost.backup/archives/backup_system_from_4p2.tar"
|
+ " /home/yunohost.backup/archives/backup_system_from_11p2.tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,10 +236,10 @@ def add_archive_system_from_4p2():
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def test_backup_only_ldap(mocker):
|
def test_backup_only_ldap():
|
||||||
# Create the backup
|
# Create the backup
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=["conf_ldap"], apps=None)
|
backup_create(name=name, system=["conf_ldap"], apps=None)
|
||||||
|
|
||||||
archives = backup_list()["archives"]
|
archives = backup_list()["archives"]
|
||||||
|
@ -253,7 +253,7 @@ def test_backup_only_ldap(mocker):
|
||||||
|
|
||||||
def test_backup_system_part_that_does_not_exists(mocker):
|
def test_backup_system_part_that_does_not_exists(mocker):
|
||||||
# Create the backup
|
# Create the backup
|
||||||
with message(mocker, "backup_hook_unknown", hook="doesnt_exist"):
|
with message("backup_hook_unknown", hook="doesnt_exist"):
|
||||||
with raiseYunohostError(mocker, "backup_nothings_done"):
|
with raiseYunohostError(mocker, "backup_nothings_done"):
|
||||||
backup_create(system=["doesnt_exist"], apps=None)
|
backup_create(system=["doesnt_exist"], apps=None)
|
||||||
|
|
||||||
|
@ -263,10 +263,10 @@ def test_backup_system_part_that_does_not_exists(mocker):
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def test_backup_and_restore_all_sys(mocker):
|
def test_backup_and_restore_all_sys():
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
# Create the backup
|
# Create the backup
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=[], apps=None)
|
backup_create(name=name, system=[], apps=None)
|
||||||
|
|
||||||
archives = backup_list()["archives"]
|
archives = backup_list()["archives"]
|
||||||
|
@ -284,7 +284,7 @@ def test_backup_and_restore_all_sys(mocker):
|
||||||
assert not os.path.exists("/etc/ssowat/conf.json")
|
assert not os.path.exists("/etc/ssowat/conf.json")
|
||||||
|
|
||||||
# Restore the backup
|
# Restore the backup
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(name=archives[0], force=True, system=[], apps=None)
|
backup_restore(name=archives[0], force=True, system=[], apps=None)
|
||||||
|
|
||||||
# Check ssowat conf is back
|
# Check ssowat conf is back
|
||||||
|
@ -292,22 +292,22 @@ def test_backup_and_restore_all_sys(mocker):
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# System restore from 3.8 #
|
# System restore from 11.2 #
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_system_archive_from_4p2
|
@pytest.mark.with_system_archive_from_11p2
|
||||||
def test_restore_system_from_Ynh4p2(monkeypatch, mocker):
|
def test_restore_system_from_Ynh11p2(monkeypatch):
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
# Backup current system
|
# Backup current system
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=[], apps=None)
|
backup_create(name=name, system=[], apps=None)
|
||||||
archives = backup_list()["archives"]
|
archives = backup_list()["archives"]
|
||||||
assert len(archives) == 2
|
assert len(archives) == 2
|
||||||
|
|
||||||
# Restore system archive from 3.8
|
# Restore system archive from 11.2
|
||||||
try:
|
try:
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
name=backup_list()["archives"][1], system=[], apps=None, force=True
|
name=backup_list()["archives"][1], system=[], apps=None, force=True
|
||||||
)
|
)
|
||||||
|
@ -336,7 +336,7 @@ def test_backup_script_failure_handling(monkeypatch, mocker):
|
||||||
# with the expected error message key
|
# with the expected error message key
|
||||||
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec)
|
monkeypatch.setattr("yunohost.backup.hook_exec", custom_hook_exec)
|
||||||
|
|
||||||
with message(mocker, "backup_app_failed", app="backup_recommended_app"):
|
with message("backup_app_failed", app="backup_recommended_app"):
|
||||||
with raiseYunohostError(mocker, "backup_nothings_done"):
|
with raiseYunohostError(mocker, "backup_nothings_done"):
|
||||||
backup_create(system=None, apps=["backup_recommended_app"])
|
backup_create(system=None, apps=["backup_recommended_app"])
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ def test_backup_not_enough_free_space(monkeypatch, mocker):
|
||||||
def test_backup_app_not_installed(mocker):
|
def test_backup_app_not_installed(mocker):
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
|
|
||||||
with message(mocker, "unbackup_app", app="wordpress"):
|
with message("unbackup_app", app="wordpress"):
|
||||||
with raiseYunohostError(mocker, "backup_nothings_done"):
|
with raiseYunohostError(mocker, "backup_nothings_done"):
|
||||||
backup_create(system=None, apps=["wordpress"])
|
backup_create(system=None, apps=["wordpress"])
|
||||||
|
|
||||||
|
@ -375,14 +375,14 @@ def test_backup_app_with_no_backup_script(mocker):
|
||||||
assert not os.path.exists(backup_script)
|
assert not os.path.exists(backup_script)
|
||||||
|
|
||||||
with message(
|
with message(
|
||||||
mocker, "backup_with_no_backup_script_for_app", app="backup_recommended_app"
|
"backup_with_no_backup_script_for_app", app="backup_recommended_app"
|
||||||
):
|
):
|
||||||
with raiseYunohostError(mocker, "backup_nothings_done"):
|
with raiseYunohostError(mocker, "backup_nothings_done"):
|
||||||
backup_create(system=None, apps=["backup_recommended_app"])
|
backup_create(system=None, apps=["backup_recommended_app"])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_backup_recommended_app_installed
|
@pytest.mark.with_backup_recommended_app_installed
|
||||||
def test_backup_app_with_no_restore_script(mocker):
|
def test_backup_app_with_no_restore_script():
|
||||||
restore_script = "/etc/yunohost/apps/backup_recommended_app/scripts/restore"
|
restore_script = "/etc/yunohost/apps/backup_recommended_app/scripts/restore"
|
||||||
os.system("rm %s" % restore_script)
|
os.system("rm %s" % restore_script)
|
||||||
assert not os.path.exists(restore_script)
|
assert not os.path.exists(restore_script)
|
||||||
|
@ -391,16 +391,16 @@ def test_backup_app_with_no_restore_script(mocker):
|
||||||
# user...
|
# user...
|
||||||
|
|
||||||
with message(
|
with message(
|
||||||
mocker, "backup_with_no_restore_script_for_app", app="backup_recommended_app"
|
"backup_with_no_restore_script_for_app", app="backup_recommended_app"
|
||||||
):
|
):
|
||||||
backup_create(system=None, apps=["backup_recommended_app"])
|
backup_create(system=None, apps=["backup_recommended_app"])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.clean_opt_dir
|
@pytest.mark.clean_opt_dir
|
||||||
def test_backup_with_different_output_directory(mocker):
|
def test_backup_with_different_output_directory():
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
# Create the backup
|
# Create the backup
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(
|
backup_create(
|
||||||
system=["conf_ynh_settings"],
|
system=["conf_ynh_settings"],
|
||||||
apps=None,
|
apps=None,
|
||||||
|
@ -420,10 +420,10 @@ def test_backup_with_different_output_directory(mocker):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.clean_opt_dir
|
@pytest.mark.clean_opt_dir
|
||||||
def test_backup_using_copy_method(mocker):
|
def test_backup_using_copy_method():
|
||||||
# Create the backup
|
# Create the backup
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(
|
backup_create(
|
||||||
system=["conf_ynh_settings"],
|
system=["conf_ynh_settings"],
|
||||||
apps=None,
|
apps=None,
|
||||||
|
@ -439,17 +439,16 @@ def test_backup_using_copy_method(mocker):
|
||||||
# App restore #
|
# App restore #
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
|
||||||
@pytest.mark.with_custom_domain("yolo.test")
|
@pytest.mark.with_custom_domain("yolo.test")
|
||||||
def test_restore_app_wordpress_from_Ynh4p2(mocker):
|
def test_restore_app_wordpress_from_Ynh11p2():
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
@pytest.mark.with_custom_domain("yolo.test")
|
@pytest.mark.with_custom_domain("yolo.test")
|
||||||
def test_restore_app_script_failure_handling(monkeypatch, mocker):
|
def test_restore_app_script_failure_handling(monkeypatch, mocker):
|
||||||
def custom_hook_exec(name, *args, **kwargs):
|
def custom_hook_exec(name, *args, **kwargs):
|
||||||
|
@ -461,7 +460,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
|
||||||
|
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
|
|
||||||
with message(mocker, "app_restore_script_failed"):
|
with message("app_restore_script_failed"):
|
||||||
with raiseYunohostError(mocker, "restore_nothings_done"):
|
with raiseYunohostError(mocker, "restore_nothings_done"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
||||||
|
@ -470,7 +469,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
def test_restore_app_not_enough_free_space(monkeypatch, mocker):
|
def test_restore_app_not_enough_free_space(monkeypatch, mocker):
|
||||||
def custom_free_space_in_directory(dirpath):
|
def custom_free_space_in_directory(dirpath):
|
||||||
return 0
|
return 0
|
||||||
|
@ -489,12 +488,12 @@ def test_restore_app_not_enough_free_space(monkeypatch, mocker):
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
def test_restore_app_not_in_backup(mocker):
|
def test_restore_app_not_in_backup(mocker):
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
assert not _is_installed("yoloswag")
|
assert not _is_installed("yoloswag")
|
||||||
|
|
||||||
with message(mocker, "backup_archive_app_not_found", app="yoloswag"):
|
with message("backup_archive_app_not_found", app="yoloswag"):
|
||||||
with raiseYunohostError(mocker, "restore_nothings_done"):
|
with raiseYunohostError(mocker, "restore_nothings_done"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
system=None, name=backup_list()["archives"][0], apps=["yoloswag"]
|
system=None, name=backup_list()["archives"][0], apps=["yoloswag"]
|
||||||
|
@ -504,12 +503,12 @@ def test_restore_app_not_in_backup(mocker):
|
||||||
assert not _is_installed("yoloswag")
|
assert not _is_installed("yoloswag")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
@pytest.mark.with_custom_domain("yolo.test")
|
@pytest.mark.with_custom_domain("yolo.test")
|
||||||
def test_restore_app_already_installed(mocker):
|
def test_restore_app_already_installed(mocker):
|
||||||
assert not _is_installed("wordpress")
|
assert not _is_installed("wordpress")
|
||||||
|
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
system=None, name=backup_list()["archives"][0], apps=["wordpress"]
|
||||||
)
|
)
|
||||||
|
@ -525,22 +524,22 @@ def test_restore_app_already_installed(mocker):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_legacy_app_installed
|
@pytest.mark.with_legacy_app_installed
|
||||||
def test_backup_and_restore_legacy_app(mocker):
|
def test_backup_and_restore_legacy_app():
|
||||||
_test_backup_and_restore_app(mocker, "legacy_app")
|
_test_backup_and_restore_app("legacy_app")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_backup_recommended_app_installed
|
@pytest.mark.with_backup_recommended_app_installed
|
||||||
def test_backup_and_restore_recommended_app(mocker):
|
def test_backup_and_restore_recommended_app():
|
||||||
_test_backup_and_restore_app(mocker, "backup_recommended_app")
|
_test_backup_and_restore_app("backup_recommended_app")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_backup_recommended_app_installed_with_ynh_restore
|
@pytest.mark.with_backup_recommended_app_installed_with_ynh_restore
|
||||||
def test_backup_and_restore_with_ynh_restore(mocker):
|
def test_backup_and_restore_with_ynh_restore():
|
||||||
_test_backup_and_restore_app(mocker, "backup_recommended_app")
|
_test_backup_and_restore_app("backup_recommended_app")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_permission_app_installed
|
@pytest.mark.with_permission_app_installed
|
||||||
def test_backup_and_restore_permission_app(mocker):
|
def test_backup_and_restore_permission_app():
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert "permissions_app.main" in res
|
assert "permissions_app.main" in res
|
||||||
assert "permissions_app.admin" in res
|
assert "permissions_app.admin" in res
|
||||||
|
@ -554,7 +553,7 @@ def test_backup_and_restore_permission_app(mocker):
|
||||||
assert res["permissions_app.admin"]["allowed"] == ["alice"]
|
assert res["permissions_app.admin"]["allowed"] == ["alice"]
|
||||||
assert res["permissions_app.dev"]["allowed"] == []
|
assert res["permissions_app.dev"]["allowed"] == []
|
||||||
|
|
||||||
_test_backup_and_restore_app(mocker, "permissions_app")
|
_test_backup_and_restore_app("permissions_app")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert "permissions_app.main" in res
|
assert "permissions_app.main" in res
|
||||||
|
@ -570,10 +569,10 @@ def test_backup_and_restore_permission_app(mocker):
|
||||||
assert res["permissions_app.dev"]["allowed"] == []
|
assert res["permissions_app.dev"]["allowed"] == []
|
||||||
|
|
||||||
|
|
||||||
def _test_backup_and_restore_app(mocker, app):
|
def _test_backup_and_restore_app(app):
|
||||||
# Create a backup of this app
|
# Create a backup of this app
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=None, apps=[app])
|
backup_create(name=name, system=None, apps=[app])
|
||||||
|
|
||||||
archives = backup_list()["archives"]
|
archives = backup_list()["archives"]
|
||||||
|
@ -590,7 +589,7 @@ def _test_backup_and_restore_app(mocker, app):
|
||||||
assert app + ".main" not in user_permission_list()["permissions"]
|
assert app + ".main" not in user_permission_list()["permissions"]
|
||||||
|
|
||||||
# Restore the app
|
# Restore the app
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(system=None, name=archives[0], apps=[app])
|
backup_restore(system=None, name=archives[0], apps=[app])
|
||||||
|
|
||||||
assert app_is_installed(app)
|
assert app_is_installed(app)
|
||||||
|
@ -616,34 +615,34 @@ def test_restore_archive_with_no_json(mocker):
|
||||||
backup_restore(name="badbackup", force=True)
|
backup_restore(name="badbackup", force=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_wordpress_archive_from_4p2
|
@pytest.mark.with_wordpress_archive_from_11p2
|
||||||
def test_restore_archive_with_bad_archive(mocker):
|
def test_restore_archive_with_bad_archive(mocker):
|
||||||
# Break the archive
|
# Break the archive
|
||||||
os.system(
|
os.system(
|
||||||
"head -n 1000 /home/yunohost.backup/archives/backup_wordpress_from_4p2.tar > /home/yunohost.backup/archives/backup_wordpress_from_4p2_bad.tar"
|
"head -n 1000 /home/yunohost.backup/archives/backup_wordpress_from_11p2.tar > /home/yunohost.backup/archives/backup_wordpress_from_11p2_bad.tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "backup_wordpress_from_4p2_bad" in backup_list()["archives"]
|
assert "backup_wordpress_from_11p2_bad" in backup_list()["archives"]
|
||||||
|
|
||||||
with raiseYunohostError(mocker, "backup_archive_corrupted"):
|
with raiseYunohostError(mocker, "backup_archive_corrupted"):
|
||||||
backup_restore(name="backup_wordpress_from_4p2_bad", force=True)
|
backup_restore(name="backup_wordpress_from_11p2_bad", force=True)
|
||||||
|
|
||||||
clean_tmp_backup_directory()
|
clean_tmp_backup_directory()
|
||||||
|
|
||||||
|
|
||||||
def test_restore_archive_with_custom_hook(mocker):
|
def test_restore_archive_with_custom_hook():
|
||||||
custom_restore_hook_folder = os.path.join(CUSTOM_HOOK_FOLDER, "restore")
|
custom_restore_hook_folder = os.path.join(CUSTOM_HOOK_FOLDER, "restore")
|
||||||
os.system("touch %s/99-yolo" % custom_restore_hook_folder)
|
os.system("touch %s/99-yolo" % custom_restore_hook_folder)
|
||||||
|
|
||||||
# Backup with custom hook system
|
# Backup with custom hook system
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=[], apps=None)
|
backup_create(name=name, system=[], apps=None)
|
||||||
archives = backup_list()["archives"]
|
archives = backup_list()["archives"]
|
||||||
assert len(archives) == 1
|
assert len(archives) == 1
|
||||||
|
|
||||||
# Restore system with custom hook
|
# Restore system with custom hook
|
||||||
with message(mocker, "restore_complete"):
|
with message("restore_complete"):
|
||||||
backup_restore(
|
backup_restore(
|
||||||
name=backup_list()["archives"][0], system=[], apps=None, force=True
|
name=backup_list()["archives"][0], system=[], apps=None, force=True
|
||||||
)
|
)
|
||||||
|
@ -651,7 +650,7 @@ def test_restore_archive_with_custom_hook(mocker):
|
||||||
os.system("rm %s/99-yolo" % custom_restore_hook_folder)
|
os.system("rm %s/99-yolo" % custom_restore_hook_folder)
|
||||||
|
|
||||||
|
|
||||||
def test_backup_binds_are_readonly(mocker, monkeypatch):
|
def test_backup_binds_are_readonly(monkeypatch):
|
||||||
def custom_mount_and_backup(self):
|
def custom_mount_and_backup(self):
|
||||||
self._organize_files()
|
self._organize_files()
|
||||||
|
|
||||||
|
@ -676,5 +675,5 @@ def test_backup_binds_are_readonly(mocker, monkeypatch):
|
||||||
|
|
||||||
# Create the backup
|
# Create the backup
|
||||||
name = random_ascii(8)
|
name = random_ascii(8)
|
||||||
with message(mocker, "backup_created", name=name):
|
with message("backup_created", name=name):
|
||||||
backup_create(name=name, system=[])
|
backup_create(name=name, system=[])
|
||||||
|
|
|
@ -39,7 +39,7 @@ def check_changeurl_app(path):
|
||||||
assert appmap[maindomain][path]["id"] == "change_url_app"
|
assert appmap[maindomain][path]["id"] == "change_url_app"
|
||||||
|
|
||||||
r = requests.get(
|
r = requests.get(
|
||||||
"https://127.0.0.1%s/" % path, headers={"domain": maindomain}, verify=False
|
"https://127.0.0.1%s/" % path, headers={"Host": maindomain}, verify=False
|
||||||
)
|
)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ def test_authenticate_with_wrong_password():
|
||||||
assert expected_msg in str(exception)
|
assert expected_msg in str(exception)
|
||||||
|
|
||||||
|
|
||||||
def test_authenticate_server_down(mocker):
|
def test_authenticate_server_down():
|
||||||
os.system("systemctl stop slapd && sleep 5")
|
os.system("systemctl stop slapd && sleep 5")
|
||||||
|
|
||||||
LDAPAuth().authenticate_credentials(credentials="alice:Yunohost")
|
LDAPAuth().authenticate_credentials(credentials="alice:Yunohost")
|
||||||
|
|
|
@ -435,8 +435,8 @@ def test_permission_list():
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_main(mocker):
|
def test_permission_create_main():
|
||||||
with message(mocker, "permission_created", permission="site.main"):
|
with message("permission_created", permission="site.main"):
|
||||||
permission_create("site.main", allowed=["all_users"], protected=False)
|
permission_create("site.main", allowed=["all_users"], protected=False)
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -446,8 +446,8 @@ def test_permission_create_main(mocker):
|
||||||
assert res["site.main"]["protected"] is False
|
assert res["site.main"]["protected"] is False
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_extra(mocker):
|
def test_permission_create_extra():
|
||||||
with message(mocker, "permission_created", permission="site.test"):
|
with message("permission_created", permission="site.test"):
|
||||||
permission_create("site.test")
|
permission_create("site.test")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -466,8 +466,8 @@ def test_permission_create_with_specific_user():
|
||||||
assert res["site.test"]["allowed"] == ["alice"]
|
assert res["site.test"]["allowed"] == ["alice"]
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_with_tile_management(mocker):
|
def test_permission_create_with_tile_management():
|
||||||
with message(mocker, "permission_created", permission="site.main"):
|
with message("permission_created", permission="site.main"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"site.main",
|
"site.main",
|
||||||
allowed=["all_users"],
|
allowed=["all_users"],
|
||||||
|
@ -483,8 +483,8 @@ def test_permission_create_with_tile_management(mocker):
|
||||||
assert res["site.main"]["show_tile"] is False
|
assert res["site.main"]["show_tile"] is False
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_with_tile_management_with_main_default_value(mocker):
|
def test_permission_create_with_tile_management_with_main_default_value():
|
||||||
with message(mocker, "permission_created", permission="site.main"):
|
with message("permission_created", permission="site.main"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"site.main",
|
"site.main",
|
||||||
allowed=["all_users"],
|
allowed=["all_users"],
|
||||||
|
@ -500,8 +500,8 @@ def test_permission_create_with_tile_management_with_main_default_value(mocker):
|
||||||
assert res["site.main"]["show_tile"] is True
|
assert res["site.main"]["show_tile"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_with_tile_management_with_not_main_default_value(mocker):
|
def test_permission_create_with_tile_management_with_not_main_default_value():
|
||||||
with message(mocker, "permission_created", permission="wiki.api"):
|
with message("permission_created", permission="wiki.api"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"wiki.api",
|
"wiki.api",
|
||||||
allowed=["all_users"],
|
allowed=["all_users"],
|
||||||
|
@ -517,8 +517,8 @@ def test_permission_create_with_tile_management_with_not_main_default_value(mock
|
||||||
assert res["wiki.api"]["show_tile"] is True
|
assert res["wiki.api"]["show_tile"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_with_urls_management_without_url(mocker):
|
def test_permission_create_with_urls_management_without_url():
|
||||||
with message(mocker, "permission_created", permission="wiki.api"):
|
with message("permission_created", permission="wiki.api"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"wiki.api", allowed=["all_users"], domain=maindomain, path="/site"
|
"wiki.api", allowed=["all_users"], domain=maindomain, path="/site"
|
||||||
)
|
)
|
||||||
|
@ -530,8 +530,8 @@ def test_permission_create_with_urls_management_without_url(mocker):
|
||||||
assert res["wiki.api"]["auth_header"] is True
|
assert res["wiki.api"]["auth_header"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_permission_create_with_urls_management_simple_domain(mocker):
|
def test_permission_create_with_urls_management_simple_domain():
|
||||||
with message(mocker, "permission_created", permission="site.main"):
|
with message("permission_created", permission="site.main"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"site.main",
|
"site.main",
|
||||||
allowed=["all_users"],
|
allowed=["all_users"],
|
||||||
|
@ -553,8 +553,8 @@ def test_permission_create_with_urls_management_simple_domain(mocker):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.other_domains(number=2)
|
@pytest.mark.other_domains(number=2)
|
||||||
def test_permission_create_with_urls_management_multiple_domain(mocker):
|
def test_permission_create_with_urls_management_multiple_domain():
|
||||||
with message(mocker, "permission_created", permission="site.main"):
|
with message("permission_created", permission="site.main"):
|
||||||
_permission_create_with_dummy_app(
|
_permission_create_with_dummy_app(
|
||||||
"site.main",
|
"site.main",
|
||||||
allowed=["all_users"],
|
allowed=["all_users"],
|
||||||
|
@ -575,14 +575,14 @@ def test_permission_create_with_urls_management_multiple_domain(mocker):
|
||||||
assert res["site.main"]["auth_header"] is True
|
assert res["site.main"]["auth_header"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_permission_delete(mocker):
|
def test_permission_delete():
|
||||||
with message(mocker, "permission_deleted", permission="wiki.main"):
|
with message("permission_deleted", permission="wiki.main"):
|
||||||
permission_delete("wiki.main", force=True)
|
permission_delete("wiki.main", force=True)
|
||||||
|
|
||||||
res = user_permission_list()["permissions"]
|
res = user_permission_list()["permissions"]
|
||||||
assert "wiki.main" not in res
|
assert "wiki.main" not in res
|
||||||
|
|
||||||
with message(mocker, "permission_deleted", permission="blog.api"):
|
with message("permission_deleted", permission="blog.api"):
|
||||||
permission_delete("blog.api", force=False)
|
permission_delete("blog.api", force=False)
|
||||||
|
|
||||||
res = user_permission_list()["permissions"]
|
res = user_permission_list()["permissions"]
|
||||||
|
@ -625,8 +625,8 @@ def test_permission_delete_main_without_force(mocker):
|
||||||
# user side functions
|
# user side functions
|
||||||
|
|
||||||
|
|
||||||
def test_permission_add_group(mocker):
|
def test_permission_add_group():
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", add="alice")
|
user_permission_update("wiki.main", add="alice")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -634,8 +634,8 @@ def test_permission_add_group(mocker):
|
||||||
assert set(res["wiki.main"]["corresponding_users"]) == {"alice", "bob"}
|
assert set(res["wiki.main"]["corresponding_users"]) == {"alice", "bob"}
|
||||||
|
|
||||||
|
|
||||||
def test_permission_remove_group(mocker):
|
def test_permission_remove_group():
|
||||||
with message(mocker, "permission_updated", permission="blog.main"):
|
with message("permission_updated", permission="blog.main"):
|
||||||
user_permission_update("blog.main", remove="alice")
|
user_permission_update("blog.main", remove="alice")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -643,8 +643,8 @@ def test_permission_remove_group(mocker):
|
||||||
assert res["blog.main"]["corresponding_users"] == []
|
assert res["blog.main"]["corresponding_users"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_permission_add_and_remove_group(mocker):
|
def test_permission_add_and_remove_group():
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", add="alice", remove="all_users")
|
user_permission_update("wiki.main", add="alice", remove="all_users")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -652,9 +652,9 @@ def test_permission_add_and_remove_group(mocker):
|
||||||
assert res["wiki.main"]["corresponding_users"] == ["alice"]
|
assert res["wiki.main"]["corresponding_users"] == ["alice"]
|
||||||
|
|
||||||
|
|
||||||
def test_permission_add_group_already_allowed(mocker):
|
def test_permission_add_group_already_allowed():
|
||||||
with message(
|
with message(
|
||||||
mocker, "permission_already_allowed", permission="blog.main", group="alice"
|
"permission_already_allowed", permission="blog.main", group="alice"
|
||||||
):
|
):
|
||||||
user_permission_update("blog.main", add="alice")
|
user_permission_update("blog.main", add="alice")
|
||||||
|
|
||||||
|
@ -663,9 +663,9 @@ def test_permission_add_group_already_allowed(mocker):
|
||||||
assert res["blog.main"]["corresponding_users"] == ["alice"]
|
assert res["blog.main"]["corresponding_users"] == ["alice"]
|
||||||
|
|
||||||
|
|
||||||
def test_permission_remove_group_already_not_allowed(mocker):
|
def test_permission_remove_group_already_not_allowed():
|
||||||
with message(
|
with message(
|
||||||
mocker, "permission_already_disallowed", permission="blog.main", group="bob"
|
"permission_already_disallowed", permission="blog.main", group="bob"
|
||||||
):
|
):
|
||||||
user_permission_update("blog.main", remove="bob")
|
user_permission_update("blog.main", remove="bob")
|
||||||
|
|
||||||
|
@ -674,8 +674,8 @@ def test_permission_remove_group_already_not_allowed(mocker):
|
||||||
assert res["blog.main"]["corresponding_users"] == ["alice"]
|
assert res["blog.main"]["corresponding_users"] == ["alice"]
|
||||||
|
|
||||||
|
|
||||||
def test_permission_reset(mocker):
|
def test_permission_reset():
|
||||||
with message(mocker, "permission_updated", permission="blog.main"):
|
with message("permission_updated", permission="blog.main"):
|
||||||
user_permission_reset("blog.main")
|
user_permission_reset("blog.main")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -693,42 +693,42 @@ def test_permission_reset_idempotency():
|
||||||
assert set(res["blog.main"]["corresponding_users"]) == {"alice", "bob"}
|
assert set(res["blog.main"]["corresponding_users"]) == {"alice", "bob"}
|
||||||
|
|
||||||
|
|
||||||
def test_permission_change_label(mocker):
|
def test_permission_change_label():
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", label="New Wiki")
|
user_permission_update("wiki.main", label="New Wiki")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert res["wiki.main"]["label"] == "New Wiki"
|
assert res["wiki.main"]["label"] == "New Wiki"
|
||||||
|
|
||||||
|
|
||||||
def test_permission_change_label_with_same_value(mocker):
|
def test_permission_change_label_with_same_value():
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", label="Wiki")
|
user_permission_update("wiki.main", label="Wiki")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert res["wiki.main"]["label"] == "Wiki"
|
assert res["wiki.main"]["label"] == "Wiki"
|
||||||
|
|
||||||
|
|
||||||
def test_permission_switch_show_tile(mocker):
|
def test_permission_switch_show_tile():
|
||||||
# Note that from the actionmap the value is passed as string, not as bool
|
# Note that from the actionmap the value is passed as string, not as bool
|
||||||
# Try with lowercase
|
# Try with lowercase
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", show_tile="false")
|
user_permission_update("wiki.main", show_tile="false")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert res["wiki.main"]["show_tile"] is False
|
assert res["wiki.main"]["show_tile"] is False
|
||||||
|
|
||||||
# Try with uppercase
|
# Try with uppercase
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", show_tile="TRUE")
|
user_permission_update("wiki.main", show_tile="TRUE")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert res["wiki.main"]["show_tile"] is True
|
assert res["wiki.main"]["show_tile"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_permission_switch_show_tile_with_same_value(mocker):
|
def test_permission_switch_show_tile_with_same_value():
|
||||||
# Note that from the actionmap the value is passed as string, not as bool
|
# Note that from the actionmap the value is passed as string, not as bool
|
||||||
with message(mocker, "permission_updated", permission="wiki.main"):
|
with message("permission_updated", permission="wiki.main"):
|
||||||
user_permission_update("wiki.main", show_tile="True")
|
user_permission_update("wiki.main", show_tile="True")
|
||||||
|
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
|
@ -806,7 +806,7 @@ def test_permission_main_url_regex():
|
||||||
|
|
||||||
def test_permission_main_url_bad_regex(mocker):
|
def test_permission_main_url_bad_regex(mocker):
|
||||||
with raiseYunohostError(mocker, "invalid_regex"):
|
with raiseYunohostError(mocker, "invalid_regex"):
|
||||||
permission_url("blog.main", url="re:/[a-z]++reboy/.*")
|
permission_url("blog.main", url="re:/[a-z]+++reboy/.*")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.other_domains(number=1)
|
@pytest.mark.other_domains(number=1)
|
||||||
|
@ -837,7 +837,7 @@ def test_permission_add_additional_regex():
|
||||||
|
|
||||||
def test_permission_add_additional_bad_regex(mocker):
|
def test_permission_add_additional_bad_regex(mocker):
|
||||||
with raiseYunohostError(mocker, "invalid_regex"):
|
with raiseYunohostError(mocker, "invalid_regex"):
|
||||||
permission_url("blog.main", add_url=["re:/[a-z]++reboy/.*"])
|
permission_url("blog.main", add_url=["re:/[a-z]+++reboy/.*"])
|
||||||
|
|
||||||
|
|
||||||
def test_permission_remove_additional_url():
|
def test_permission_remove_additional_url():
|
||||||
|
@ -1131,7 +1131,7 @@ def test_permission_app_propagation_on_ssowat():
|
||||||
def test_permission_legacy_app_propagation_on_ssowat():
|
def test_permission_legacy_app_propagation_on_ssowat():
|
||||||
app_install(
|
app_install(
|
||||||
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
|
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
|
||||||
args="domain=%s&domain_2=%s&path=%s&is_public=1"
|
args="domain=%s&domain_2=%s&path=%s&is_public=0"
|
||||||
% (maindomain, other_domains[0], "/legacy"),
|
% (maindomain, other_domains[0], "/legacy"),
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
|
@ -1139,12 +1139,12 @@ def test_permission_legacy_app_propagation_on_ssowat():
|
||||||
# App is configured as public by default using the legacy unprotected_uri mechanics
|
# App is configured as public by default using the legacy unprotected_uri mechanics
|
||||||
# It should automatically be migrated during the install
|
# It should automatically be migrated during the install
|
||||||
res = user_permission_list(full=True)["permissions"]
|
res = user_permission_list(full=True)["permissions"]
|
||||||
assert "visitors" in res["legacy_app.main"]["allowed"]
|
assert "visitors" not in res["legacy_app.main"]["allowed"]
|
||||||
assert "all_users" in res["legacy_app.main"]["allowed"]
|
assert "all_users" in res["legacy_app.main"]["allowed"]
|
||||||
|
|
||||||
app_webroot = "https://%s/legacy" % maindomain
|
app_webroot = "https://%s/legacy" % maindomain
|
||||||
|
|
||||||
assert can_access_webpage(app_webroot, logged_as=None)
|
assert not can_access_webpage(app_webroot, logged_as=None)
|
||||||
assert can_access_webpage(app_webroot, logged_as="alice")
|
assert can_access_webpage(app_webroot, logged_as="alice")
|
||||||
|
|
||||||
# Try to update the permission and check that permissions are still consistent
|
# Try to update the permission and check that permissions are still consistent
|
||||||
|
|
|
@ -87,7 +87,7 @@ def test_ssh_conf_unmanaged():
|
||||||
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
||||||
|
|
||||||
|
|
||||||
def test_ssh_conf_unmanaged_and_manually_modified(mocker):
|
def test_ssh_conf_unmanaged_and_manually_modified():
|
||||||
_force_clear_hashes([SSHD_CONFIG])
|
_force_clear_hashes([SSHD_CONFIG])
|
||||||
os.system("echo ' ' >> %s" % SSHD_CONFIG)
|
os.system("echo ' ' >> %s" % SSHD_CONFIG)
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ def test_ssh_conf_unmanaged_and_manually_modified(mocker):
|
||||||
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
||||||
assert SSHD_CONFIG in manually_modified_files()
|
assert SSHD_CONFIG in manually_modified_files()
|
||||||
|
|
||||||
with message(mocker, "regenconf_need_to_explicitly_specify_ssh"):
|
with message("regenconf_need_to_explicitly_specify_ssh"):
|
||||||
regen_conf(force=True)
|
regen_conf(force=True)
|
||||||
|
|
||||||
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
assert SSHD_CONFIG in _get_conf_hashes("ssh")
|
||||||
|
|
|
@ -91,8 +91,8 @@ def test_list_groups():
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def test_create_user(mocker):
|
def test_create_user():
|
||||||
with message(mocker, "user_created"):
|
with message("user_created"):
|
||||||
user_create("albert", maindomain, "test123Ynh", fullname="Albert Good")
|
user_create("albert", maindomain, "test123Ynh", fullname="Albert Good")
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -102,8 +102,8 @@ def test_create_user(mocker):
|
||||||
assert "albert" in group_res["all_users"]["members"]
|
assert "albert" in group_res["all_users"]["members"]
|
||||||
|
|
||||||
|
|
||||||
def test_del_user(mocker):
|
def test_del_user():
|
||||||
with message(mocker, "user_deleted"):
|
with message("user_deleted"):
|
||||||
user_delete("alice")
|
user_delete("alice")
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -112,7 +112,7 @@ def test_del_user(mocker):
|
||||||
assert "alice" not in group_res["all_users"]["members"]
|
assert "alice" not in group_res["all_users"]["members"]
|
||||||
|
|
||||||
|
|
||||||
def test_import_user(mocker):
|
def test_import_user():
|
||||||
import csv
|
import csv
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ def test_import_user(mocker):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
csv_io.seek(0)
|
csv_io.seek(0)
|
||||||
with message(mocker, "user_import_success"):
|
with message("user_import_success"):
|
||||||
user_import(csv_io, update=True, delete=True)
|
user_import(csv_io, update=True, delete=True)
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -171,7 +171,7 @@ def test_import_user(mocker):
|
||||||
assert "alice" not in group_res["dev"]["members"]
|
assert "alice" not in group_res["dev"]["members"]
|
||||||
|
|
||||||
|
|
||||||
def test_export_user(mocker):
|
def test_export_user():
|
||||||
result = user_export()
|
result = user_export()
|
||||||
should_be = (
|
should_be = (
|
||||||
"username;firstname;lastname;password;mail;mail-alias;mail-forward;mailbox-quota;groups\r\n"
|
"username;firstname;lastname;password;mail;mail-alias;mail-forward;mailbox-quota;groups\r\n"
|
||||||
|
@ -182,8 +182,8 @@ def test_export_user(mocker):
|
||||||
assert result == should_be
|
assert result == should_be
|
||||||
|
|
||||||
|
|
||||||
def test_create_group(mocker):
|
def test_create_group():
|
||||||
with message(mocker, "group_created", group="adminsys"):
|
with message("group_created", group="adminsys"):
|
||||||
user_group_create("adminsys")
|
user_group_create("adminsys")
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -192,8 +192,8 @@ def test_create_group(mocker):
|
||||||
assert group_res["adminsys"]["members"] == []
|
assert group_res["adminsys"]["members"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_del_group(mocker):
|
def test_del_group():
|
||||||
with message(mocker, "group_deleted", group="dev"):
|
with message("group_deleted", group="dev"):
|
||||||
user_group_delete("dev")
|
user_group_delete("dev")
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -262,46 +262,40 @@ def test_del_group_that_does_not_exist(mocker):
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def test_update_user(mocker):
|
def test_update_user():
|
||||||
with message(mocker, "user_updated"):
|
with message("user_updated"):
|
||||||
user_update("alice", firstname="NewName", lastname="NewLast")
|
|
||||||
|
|
||||||
info = user_info("alice")
|
|
||||||
assert info["fullname"] == "NewName NewLast"
|
|
||||||
|
|
||||||
with message(mocker, "user_updated"):
|
|
||||||
user_update("alice", fullname="New2Name New2Last")
|
user_update("alice", fullname="New2Name New2Last")
|
||||||
|
|
||||||
info = user_info("alice")
|
info = user_info("alice")
|
||||||
assert info["fullname"] == "New2Name New2Last"
|
assert info["fullname"] == "New2Name New2Last"
|
||||||
|
|
||||||
|
|
||||||
def test_update_group_add_user(mocker):
|
def test_update_group_add_user():
|
||||||
with message(mocker, "group_updated", group="dev"):
|
with message("group_updated", group="dev"):
|
||||||
user_group_update("dev", add=["bob"])
|
user_group_update("dev", add=["bob"])
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
assert set(group_res["dev"]["members"]) == {"alice", "bob"}
|
assert set(group_res["dev"]["members"]) == {"alice", "bob"}
|
||||||
|
|
||||||
|
|
||||||
def test_update_group_add_user_already_in(mocker):
|
def test_update_group_add_user_already_in():
|
||||||
with message(mocker, "group_user_already_in_group", user="bob", group="apps"):
|
with message("group_user_already_in_group", user="bob", group="apps"):
|
||||||
user_group_update("apps", add=["bob"])
|
user_group_update("apps", add=["bob"])
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
assert group_res["apps"]["members"] == ["bob"]
|
assert group_res["apps"]["members"] == ["bob"]
|
||||||
|
|
||||||
|
|
||||||
def test_update_group_remove_user(mocker):
|
def test_update_group_remove_user():
|
||||||
with message(mocker, "group_updated", group="apps"):
|
with message("group_updated", group="apps"):
|
||||||
user_group_update("apps", remove=["bob"])
|
user_group_update("apps", remove=["bob"])
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
assert group_res["apps"]["members"] == []
|
assert group_res["apps"]["members"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_update_group_remove_user_not_already_in(mocker):
|
def test_update_group_remove_user_not_already_in():
|
||||||
with message(mocker, "group_user_not_in_group", user="jack", group="apps"):
|
with message("group_user_not_in_group", user="jack", group="apps"):
|
||||||
user_group_update("apps", remove=["jack"])
|
user_group_update("apps", remove=["jack"])
|
||||||
|
|
||||||
group_res = user_group_list()["groups"]
|
group_res = user_group_list()["groups"]
|
||||||
|
@ -315,7 +309,7 @@ def test_update_group_remove_user_not_already_in(mocker):
|
||||||
|
|
||||||
def test_update_user_that_doesnt_exist(mocker):
|
def test_update_user_that_doesnt_exist(mocker):
|
||||||
with raiseYunohostError(mocker, "user_unknown"):
|
with raiseYunohostError(mocker, "user_unknown"):
|
||||||
user_update("doesnt_exist", firstname="NewName", lastname="NewLast")
|
user_update("doesnt_exist", fullname="Foo Bar")
|
||||||
|
|
||||||
|
|
||||||
def test_update_group_that_doesnt_exist(mocker):
|
def test_update_group_that_doesnt_exist(mocker):
|
||||||
|
|
|
@ -24,9 +24,9 @@ import time
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from packaging import version
|
from packaging import version
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.process import call_async_output
|
from moulinette.utils.process import call_async_output
|
||||||
from moulinette.utils.filesystem import read_yaml, write_to_yaml, cp, mkdir, rm, chown
|
from moulinette.utils.filesystem import read_yaml, write_to_yaml, cp, mkdir, rm, chown
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ from yunohost.log import is_unit_operation, OperationLogger
|
||||||
|
|
||||||
MIGRATIONS_STATE_PATH = "/etc/yunohost/migrations.yaml"
|
MIGRATIONS_STATE_PATH = "/etc/yunohost/migrations.yaml"
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.tools")
|
logger = getLogger("yunohost.tools")
|
||||||
|
|
||||||
|
|
||||||
def tools_versions():
|
def tools_versions():
|
||||||
|
|
49
src/user.py
49
src/user.py
|
@ -25,9 +25,9 @@ import random
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import copy
|
import copy
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
@ -35,7 +35,7 @@ from yunohost.service import service_status
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.utils.system import binary_to_human
|
from yunohost.utils.system import binary_to_human
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.user")
|
logger = getLogger("yunohost.user")
|
||||||
|
|
||||||
FIELDS_FOR_IMPORT = {
|
FIELDS_FOR_IMPORT = {
|
||||||
"username": r"^[a-z0-9_]+$",
|
"username": r"^[a-z0-9_]+$",
|
||||||
|
@ -141,33 +141,20 @@ def user_create(
|
||||||
domain,
|
domain,
|
||||||
password,
|
password,
|
||||||
fullname=None,
|
fullname=None,
|
||||||
firstname=None,
|
|
||||||
lastname=None,
|
|
||||||
mailbox_quota="0",
|
mailbox_quota="0",
|
||||||
admin=False,
|
admin=False,
|
||||||
from_import=False,
|
from_import=False,
|
||||||
loginShell=None,
|
loginShell=None,
|
||||||
):
|
):
|
||||||
if firstname or lastname:
|
|
||||||
logger.warning(
|
|
||||||
"Options --firstname / --lastname of 'yunohost user create' are deprecated. We recommend using --fullname instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
if not fullname or not fullname.strip():
|
if not fullname or not fullname.strip():
|
||||||
if not firstname.strip():
|
raise YunohostValidationError(
|
||||||
raise YunohostValidationError(
|
"You should specify the fullname of the user using option -F"
|
||||||
"You should specify the fullname of the user using option -F"
|
)
|
||||||
)
|
fullname = fullname.strip()
|
||||||
lastname = (
|
firstname = fullname.split()[0]
|
||||||
lastname or " "
|
lastname = (
|
||||||
) # Stupid hack because LDAP requires the sn/lastname attr, but it accepts a single whitespace...
|
" ".join(fullname.split()[1:]) or " "
|
||||||
fullname = f"{firstname} {lastname}".strip()
|
) # Stupid hack because LDAP requires the sn/lastname attr, but it accepts a single whitespace...
|
||||||
else:
|
|
||||||
fullname = fullname.strip()
|
|
||||||
firstname = fullname.split()[0]
|
|
||||||
lastname = (
|
|
||||||
" ".join(fullname.split()[1:]) or " "
|
|
||||||
) # Stupid hack because LDAP requires the sn/lastname attr, but it accepts a single whitespace...
|
|
||||||
|
|
||||||
from yunohost.domain import domain_list, _get_maindomain, _assert_domain_exists
|
from yunohost.domain import domain_list, _get_maindomain, _assert_domain_exists
|
||||||
from yunohost.hook import hook_callback
|
from yunohost.hook import hook_callback
|
||||||
|
@ -364,8 +351,6 @@ def user_delete(operation_logger, username, purge=False, from_import=False):
|
||||||
def user_update(
|
def user_update(
|
||||||
operation_logger,
|
operation_logger,
|
||||||
username,
|
username,
|
||||||
firstname=None,
|
|
||||||
lastname=None,
|
|
||||||
mail=None,
|
mail=None,
|
||||||
change_password=None,
|
change_password=None,
|
||||||
add_mailforward=None,
|
add_mailforward=None,
|
||||||
|
@ -377,17 +362,15 @@ def user_update(
|
||||||
fullname=None,
|
fullname=None,
|
||||||
loginShell=None,
|
loginShell=None,
|
||||||
):
|
):
|
||||||
if firstname or lastname:
|
|
||||||
logger.warning(
|
|
||||||
"Options --firstname / --lastname of 'yunohost user create' are deprecated. We recommend using --fullname instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
if fullname and fullname.strip():
|
if fullname and fullname.strip():
|
||||||
fullname = fullname.strip()
|
fullname = fullname.strip()
|
||||||
firstname = fullname.split()[0]
|
firstname = fullname.split()[0]
|
||||||
lastname = (
|
lastname = (
|
||||||
" ".join(fullname.split()[1:]) or " "
|
" ".join(fullname.split()[1:]) or " "
|
||||||
) # Stupid hack because LDAP requires the sn/lastname attr, but it accepts a single whitespace...
|
) # Stupid hack because LDAP requires the sn/lastname attr, but it accepts a single whitespace...
|
||||||
|
else:
|
||||||
|
firstname = None
|
||||||
|
lastname = None
|
||||||
|
|
||||||
from yunohost.domain import domain_list
|
from yunohost.domain import domain_list
|
||||||
from yunohost.app import app_ssowatconf
|
from yunohost.app import app_ssowatconf
|
||||||
|
@ -884,8 +867,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
|
|
||||||
user_update(
|
user_update(
|
||||||
new_infos["username"],
|
new_infos["username"],
|
||||||
firstname=new_infos["firstname"],
|
fullname=(new_infos["firstname"] + " " + new_infos["lastname"]).strip(),
|
||||||
lastname=new_infos["lastname"],
|
|
||||||
change_password=new_infos["password"],
|
change_password=new_infos["password"],
|
||||||
mailbox_quota=new_infos["mailbox-quota"],
|
mailbox_quota=new_infos["mailbox-quota"],
|
||||||
mail=new_infos["mail"],
|
mail=new_infos["mail"],
|
||||||
|
@ -930,8 +912,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
user["password"],
|
user["password"],
|
||||||
user["mailbox-quota"],
|
user["mailbox-quota"],
|
||||||
from_import=True,
|
from_import=True,
|
||||||
firstname=user["firstname"],
|
fullname=(user["firstname"] + " " + user["lastname"]).strip(),
|
||||||
lastname=user["lastname"],
|
|
||||||
)
|
)
|
||||||
update(user)
|
update(user)
|
||||||
result["created"] += 1
|
result["created"] += 1
|
||||||
|
|
|
@ -22,11 +22,11 @@ import re
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.interfaces.cli import colorize
|
from moulinette.interfaces.cli import colorize
|
||||||
from moulinette.utils.filesystem import mkdir, read_toml, read_yaml, write_to_yaml
|
from moulinette.utils.filesystem import mkdir, read_toml, read_yaml, write_to_yaml
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.form import (
|
from yunohost.utils.form import (
|
||||||
OPTIONS,
|
OPTIONS,
|
||||||
|
@ -40,7 +40,7 @@ from yunohost.utils.form import (
|
||||||
)
|
)
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.configpanel")
|
logger = getLogger("yunohost.configpanel")
|
||||||
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,11 +160,15 @@ class ConfigPanel:
|
||||||
result[key] = {"ask": ask}
|
result[key] = {"ask": ask}
|
||||||
if "current_value" in option:
|
if "current_value" in option:
|
||||||
question_class = OPTIONS[option.get("type", OptionType.string)]
|
question_class = OPTIONS[option.get("type", OptionType.string)]
|
||||||
result[key]["value"] = question_class.humanize(
|
if hasattr(question_class, "humanize"):
|
||||||
option["current_value"], option
|
result[key]["value"] = question_class.humanize(
|
||||||
)
|
option["current_value"], option
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
result[key]["value"] = option["current_value"]
|
||||||
|
|
||||||
# FIXME: semantics, technically here this is not about a prompt...
|
# FIXME: semantics, technically here this is not about a prompt...
|
||||||
if question_class.hide_user_input_in_prompt:
|
if getattr(question_class, "hide_user_input_in_prompt", None):
|
||||||
result[key][
|
result[key][
|
||||||
"value"
|
"value"
|
||||||
] = "**************" # Prevent displaying password in `config get`
|
] = "**************" # Prevent displaying password in `config get`
|
||||||
|
@ -610,7 +614,7 @@ class ConfigPanel:
|
||||||
{
|
{
|
||||||
question.id: question.value
|
question.id: question.value
|
||||||
for question in questions
|
for question in questions
|
||||||
if question.value is not None
|
if not question.readonly and question.value is not None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,16 @@ import tempfile
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Callable, Dict, List, Literal, Mapping, Optional, Union
|
from typing import Any, Callable, Dict, List, Literal, Mapping, Optional, Union
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.interfaces.cli import colorize
|
from moulinette.interfaces.cli import colorize
|
||||||
from moulinette.utils.filesystem import read_file, write_to_file
|
from moulinette.utils.filesystem import read_file, write_to_file
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.form")
|
logger = getLogger("yunohost.form")
|
||||||
|
|
||||||
Context = dict[str, Any]
|
Context = dict[str, Any]
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import glob
|
import glob
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
read_file,
|
read_file,
|
||||||
write_to_file,
|
write_to_file,
|
||||||
|
@ -32,7 +33,7 @@ from moulinette.utils.filesystem import (
|
||||||
from yunohost.utils.error import YunohostValidationError
|
from yunohost.utils.error import YunohostValidationError
|
||||||
|
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.legacy")
|
logger = getLogger("yunohost.utils.legacy")
|
||||||
|
|
||||||
LEGACY_PERMISSION_LABEL = {
|
LEGACY_PERMISSION_LABEL = {
|
||||||
("nextcloud", "skipped"): "api", # .well-known
|
("nextcloud", "skipped"): "api", # .well-known
|
||||||
|
@ -163,32 +164,45 @@ def translate_legacy_default_app_in_ssowant_conf_json_persistent():
|
||||||
|
|
||||||
|
|
||||||
LEGACY_PHP_VERSION_REPLACEMENTS = [
|
LEGACY_PHP_VERSION_REPLACEMENTS = [
|
||||||
("/etc/php5", "/etc/php/7.4"),
|
("/etc/php5", "/etc/php/8.2"),
|
||||||
("/etc/php/7.0", "/etc/php/7.4"),
|
("/etc/php/7.0", "/etc/php/8.2"),
|
||||||
("/etc/php/7.3", "/etc/php/7.4"),
|
("/etc/php/7.3", "/etc/php/8.2"),
|
||||||
("/var/run/php5-fpm", "/var/run/php/php7.4-fpm"),
|
("/etc/php/7.4", "/etc/php/8.2"),
|
||||||
("/var/run/php/php7.0-fpm", "/var/run/php/php7.4-fpm"),
|
("/var/run/php5-fpm", "/var/run/php/php8.2-fpm"),
|
||||||
("/var/run/php/php7.3-fpm", "/var/run/php/php7.4-fpm"),
|
("/var/run/php/php7.0-fpm", "/var/run/php/php8.2-fpm"),
|
||||||
("php5", "php7.4"),
|
("/var/run/php/php7.3-fpm", "/var/run/php/php8.2-fpm"),
|
||||||
("php7.0", "php7.4"),
|
("/var/run/php/php7.4-fpm", "/var/run/php/php8.2-fpm"),
|
||||||
("php7.3", "php7.4"),
|
("php5", "php8.2"),
|
||||||
('YNH_PHP_VERSION="7.3"', 'YNH_PHP_VERSION="7.4"'),
|
("php7.0", "php8.2"),
|
||||||
|
("php7.3", "php8.2"),
|
||||||
|
("php7.4", "php8.2"),
|
||||||
|
('YNH_PHP_VERSION="7.3"', 'YNH_PHP_VERSION="8.2"'),
|
||||||
|
('YNH_PHP_VERSION="7.4"', 'YNH_PHP_VERSION="8.2"'),
|
||||||
(
|
(
|
||||||
'phpversion="${phpversion:-7.0}"',
|
'phpversion="${phpversion:-7.0}"',
|
||||||
'phpversion="${phpversion:-7.4}"',
|
'phpversion="${phpversion:-8.2}"',
|
||||||
), # Many helpers like the composer ones use 7.0 by default ...
|
), # Many helpers like the composer ones use 7.0 by default ...
|
||||||
(
|
(
|
||||||
'phpversion="${phpversion:-7.3}"',
|
'phpversion="${phpversion:-7.3}"',
|
||||||
|
'phpversion="${phpversion:-8.2}"',
|
||||||
|
), # Many helpers like the composer ones use 7.0 by default ...
|
||||||
|
(
|
||||||
'phpversion="${phpversion:-7.4}"',
|
'phpversion="${phpversion:-7.4}"',
|
||||||
|
'phpversion="${phpversion:-8.2}"',
|
||||||
), # Many helpers like the composer ones use 7.0 by default ...
|
), # Many helpers like the composer ones use 7.0 by default ...
|
||||||
(
|
(
|
||||||
'"$phpversion" == "7.0"',
|
'"$phpversion" == "7.0"',
|
||||||
'$(bc <<< "$phpversion >= 7.4") -eq 1',
|
'$(bc <<< "$phpversion >= 8.2") -eq 1',
|
||||||
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
||||||
(
|
(
|
||||||
'"$phpversion" == "7.3"',
|
'"$phpversion" == "7.3"',
|
||||||
'$(bc <<< "$phpversion >= 7.4") -eq 1',
|
'$(bc <<< "$phpversion >= 8.2") -eq 1',
|
||||||
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
||||||
|
(
|
||||||
|
'"$phpversion" == "7.4"',
|
||||||
|
'$(bc <<< "$phpversion >= 8.2") -eq 1',
|
||||||
|
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,15 +231,16 @@ def _patch_legacy_php_versions(app_folder):
|
||||||
def _patch_legacy_php_versions_in_settings(app_folder):
|
def _patch_legacy_php_versions_in_settings(app_folder):
|
||||||
settings = read_yaml(os.path.join(app_folder, "settings.yml"))
|
settings = read_yaml(os.path.join(app_folder, "settings.yml"))
|
||||||
|
|
||||||
if settings.get("fpm_config_dir") in ["/etc/php/7.0/fpm", "/etc/php/7.3/fpm"]:
|
if settings.get("fpm_config_dir") in ["/etc/php/7.0/fpm", "/etc/php/7.3/fpm", "/etc/php/7.4/fpm"]:
|
||||||
settings["fpm_config_dir"] = "/etc/php/7.4/fpm"
|
settings["fpm_config_dir"] = "/etc/php/8.2/fpm"
|
||||||
if settings.get("fpm_service") in ["php7.0-fpm", "php7.3-fpm"]:
|
if settings.get("fpm_service") in ["php7.0-fpm", "php7.3-fpm", "php7.4-fpm"]:
|
||||||
settings["fpm_service"] = "php7.4-fpm"
|
settings["fpm_service"] = "php8.2-fpm"
|
||||||
if settings.get("phpversion") in ["7.0", "7.3"]:
|
if settings.get("phpversion") in ["7.0", "7.3", "7.4"]:
|
||||||
settings["phpversion"] = "7.4"
|
settings["phpversion"] = "8.2"
|
||||||
|
|
||||||
# We delete these checksums otherwise the file will appear as manually modified
|
# We delete these checksums otherwise the file will appear as manually modified
|
||||||
list_to_remove = [
|
list_to_remove = [
|
||||||
|
"checksum__etc_php_7.4_fpm_pool",
|
||||||
"checksum__etc_php_7.3_fpm_pool",
|
"checksum__etc_php_7.3_fpm_pool",
|
||||||
"checksum__etc_php_7.0_fpm_pool",
|
"checksum__etc_php_7.0_fpm_pool",
|
||||||
"checksum__etc_nginx_conf.d",
|
"checksum__etc_nginx_conf.d",
|
||||||
|
|
|
@ -23,11 +23,11 @@ import random
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Dict, Any, List, Union
|
from typing import Dict, Any, List, Union
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.text import random_ascii
|
from moulinette.utils.text import random_ascii
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.log import getActionLogger
|
|
||||||
from moulinette.utils.filesystem import mkdir, chown, chmod, write_to_file
|
from moulinette.utils.filesystem import mkdir, chown, chmod, write_to_file
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
rm,
|
rm,
|
||||||
|
@ -35,7 +35,7 @@ from moulinette.utils.filesystem import (
|
||||||
from yunohost.utils.system import system_arch
|
from yunohost.utils.system import system_arch
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.app_resources")
|
logger = getLogger("yunohost.utils.resources")
|
||||||
|
|
||||||
|
|
||||||
class AppResourceManager:
|
class AppResourceManager:
|
||||||
|
@ -1337,8 +1337,8 @@ class DatabaseAppResource(AppResource):
|
||||||
|
|
||||||
def provision_or_update(self, context: Dict = {}):
|
def provision_or_update(self, context: Dict = {}):
|
||||||
# This is equivalent to ynh_sanitize_dbid
|
# This is equivalent to ynh_sanitize_dbid
|
||||||
db_name = self.app.replace("-", "_").replace(".", "_")
|
db_user = self.app.replace("-", "_").replace(".", "_")
|
||||||
db_user = db_name
|
db_name = self.get_setting("db_name") or db_user
|
||||||
self.set_setting("db_name", db_name)
|
self.set_setting("db_name", db_name)
|
||||||
self.set_setting("db_user", db_user)
|
self.set_setting("db_user", db_user)
|
||||||
|
|
||||||
|
@ -1372,8 +1372,8 @@ class DatabaseAppResource(AppResource):
|
||||||
)
|
)
|
||||||
|
|
||||||
def deprovision(self, context: Dict = {}):
|
def deprovision(self, context: Dict = {}):
|
||||||
db_name = self.app.replace("-", "_").replace(".", "_")
|
db_user = self.app.replace("-", "_").replace(".", "_")
|
||||||
db_user = db_name
|
db_name = self.get_setting("db_name") or db_user
|
||||||
|
|
||||||
if self.dbtype == "mysql":
|
if self.dbtype == "mysql":
|
||||||
self._run_script(
|
self._run_script(
|
||||||
|
|
18
tox.ini
18
tox.ini
|
@ -1,15 +1,15 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py39-{lint,invalidcode},py39-black-{run,check}
|
envlist = py311-{lint,invalidcode},py311-black-{run,check}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
skip_install=True
|
skip_install=True
|
||||||
deps =
|
deps =
|
||||||
py39-{lint,invalidcode}: flake8
|
py311-{lint,invalidcode}: flake8
|
||||||
py39-black-{run,check}: black
|
py311-black-{run,check}: black
|
||||||
py39-mypy: mypy >= 0.900
|
py311-mypy: mypy >= 0.900
|
||||||
commands =
|
commands =
|
||||||
py39-lint: flake8 src doc maintenance tests --ignore E402,E501,E203,W503,E741 --exclude src/tests,src/vendor
|
py311-lint: flake8 src doc maintenance tests --ignore E402,E501,E203,W503,E741 --exclude src/tests,src/vendor
|
||||||
py39-invalidcode: flake8 src bin maintenance --exclude src/tests,src/vendor --select F,E722,W605
|
py311-invalidcode: flake8 src bin maintenance --exclude src/tests,src/vendor --select F,E722,W605
|
||||||
py39-black-check: black --check --diff bin src doc maintenance tests
|
py311-black-check: black --check --diff bin src doc maintenance tests
|
||||||
py39-black-run: black bin src doc maintenance tests
|
py311-black-run: black bin src doc maintenance tests
|
||||||
py39-mypy: mypy --ignore-missing-import --install-types --non-interactive --follow-imports silent src/ --exclude (acme_tiny|migrations)
|
py311-mypy: mypy --ignore-missing-import --install-types --non-interactive --follow-imports silent src/ --exclude (acme_tiny|migrations)
|
||||||
|
|
Loading…
Add table
Reference in a new issue