Merge remote-tracking branch 'origin/dev' into bookworm

This commit is contained in:
Alexandre Aubin 2023-07-04 18:10:25 +02:00
commit bdc296f858
12 changed files with 71 additions and 29 deletions

View file

@ -1,3 +1,3 @@
location / { location / {
return 302 https://$http_host/yunohost/admin; return 302 https://$host/yunohost/admin;
} }

View file

@ -25,7 +25,7 @@ server {
{# Note that this != "False" is meant to be failure-safe, in the case the redrect_to_https would happen to contain empty string or whatever value. We absolutely don't want to disable the HTTPS redirect *except* when it's explicitly being asked to be disabled. #} {# Note that this != "False" is meant to be failure-safe, in the case the redrect_to_https would happen to contain empty string or whatever value. We absolutely don't want to disable the HTTPS redirect *except* when it's explicitly being asked to be disabled. #}
{% if redirect_to_https != "False" %} {% if redirect_to_https != "False" %}
location / { location / {
return 301 https://$http_host$request_uri; return 301 https://$host$request_uri;
} }
{# The app config snippets are not included in the HTTP conf unless HTTPS redirect is disabled, because app's location may blocks will conflict or bypass/ignore the HTTPS redirection. #} {# The app config snippets are not included in the HTTP conf unless HTTPS redirect is disabled, because app's location may blocks will conflict or bypass/ignore the HTTPS redirection. #}
{% else %} {% else %}

View file

@ -4,7 +4,7 @@ location /yunohost/api/ {
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host; proxy_set_header Host $host;
{% if webadmin_allowlist_enabled == "True" %} {% if webadmin_allowlist_enabled == "True" %}
{% for ip in webadmin_allowlist.split(',') %} {% for ip in webadmin_allowlist.split(',') %}

7
debian/changelog vendored
View file

@ -4,6 +4,13 @@ yunohost (12.0.0) unstable; urgency=low
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 04 May 2023 20:30:19 +0200 -- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 04 May 2023 20:30:19 +0200
yunohost (11.1.21.4) stable; urgency=low
- regenconf: Get rid of previous tmp hack about /dev/null for people that went through the very first 11.1.21, because it's causing issue in unpriviledged LXC or similar context (8242cab7)
- apps: don't attempt to del password key if it doesn't exist (29338f79)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 14 Jun 2023 15:48:33 +0200
yunohost (11.1.21.3) stable; urgency=low yunohost (11.1.21.3) stable; urgency=low
- Fix again /var/www/.well-known/ynh-diagnosis/ perms which are too broad and could be exploited to serve malicious files x_x (84984ad8) - Fix again /var/www/.well-known/ynh-diagnosis/ perms which are too broad and could be exploited to serve malicious files x_x (84984ad8)

View file

@ -124,7 +124,7 @@ ynh_remove_apps() {
# Requires YunoHost version 11.0.* or higher, and that the app relies on packaging v2 or higher. # Requires YunoHost version 11.0.* or higher, and that the app relies on packaging v2 or higher.
# The spawned shell will have environment variables loaded and environment files sourced # The spawned shell will have environment variables loaded and environment files sourced
# from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting). # from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting).
# If the app relies on a specific PHP version, then `php` will be aliased that version. # If the app relies on a specific PHP version, then `php` will be aliased that version. The PHP command will also be appended with the `phpflags` settings.
ynh_spawn_app_shell() { ynh_spawn_app_shell() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=a local legacy_args=a
@ -176,9 +176,10 @@ ynh_spawn_app_shell() {
# Force `php` to its intended version # Force `php` to its intended version
# We use `eval`+`export` since `alias` is not propagated to subshells, even with `export` # We use `eval`+`export` since `alias` is not propagated to subshells, even with `export`
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
local phpflags=$(ynh_app_setting_get --app=$app --key=phpflags)
if [ -n "$phpversion" ] if [ -n "$phpversion" ]
then then
eval "php() { php${phpversion} \"\$@\"; }" eval "php() { php${phpversion} ${phpflags} \"\$@\"; }"
export -f php export -f php
fi fi

View file

@ -872,6 +872,8 @@ app:
### app_shell() ### app_shell()
shell: shell:
action_help: Open an interactive shell with the app environment already loaded action_help: Open an interactive shell with the app environment already loaded
# Here we set a GET only not to lock the command line. There is no actual API endpoint for app_shell()
api: GET /apps/<app>/shell
arguments: arguments:
app: app:
help: App ID help: App ID

View file

@ -84,7 +84,7 @@ re_app_instance_name = re.compile(
) )
APP_REPO_URL = re.compile( APP_REPO_URL = re.compile(
r"^https://[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_./~]+/[a-zA-Z0-9-_.]+_ynh(/?(-/)?tree/[a-zA-Z0-9-_.]+)?(\.git)?/?$" r"^https://[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_./~]+/[a-zA-Z0-9-_.]+_ynh(/?(-/)?(tree|src/(branch|tag|commit))/[a-zA-Z0-9-_.]+)?(\.git)?/?$"
) )
APP_FILES_TO_COPY = [ APP_FILES_TO_COPY = [
@ -1193,6 +1193,7 @@ def app_install(
for question in questions: for question in questions:
# Or should it be more generally question.redact ? # Or should it be more generally question.redact ?
if question.type == "password": if question.type == "password":
if f"YNH_APP_ARG_{question.name.upper()}" in env_dict_for_logging:
del env_dict_for_logging[f"YNH_APP_ARG_{question.name.upper()}"] del env_dict_for_logging[f"YNH_APP_ARG_{question.name.upper()}"]
if question.name in env_dict_for_logging: if question.name in env_dict_for_logging:
del env_dict_for_logging[question.name] del env_dict_for_logging[question.name]

View file

@ -182,6 +182,10 @@ class MyDiagnoser(Diagnoser):
if success != "ok": if success != "ok":
return None return None
else: else:
if type_ == "TXT" and isinstance(answers,list):
for part in answers:
if part.startswith('"v=spf1'):
return part
return answers[0] if len(answers) == 1 else answers return answers[0] if len(answers) == 1 else answers
def current_record_match_expected(self, r): def current_record_match_expected(self, r):

View file

@ -331,7 +331,7 @@ def firewall_reload(skip_upnp=False):
# Refresh port forwarding with UPnP # Refresh port forwarding with UPnP
firewall_upnp(no_refresh=False) firewall_upnp(no_refresh=False)
_run_service_command("reload", "fail2ban") _run_service_command("restart", "fail2ban")
if errors: if errors:
logger.warning(m18n.n("firewall_rules_cmd_failed")) logger.warning(m18n.n("firewall_rules_cmd_failed"))

View file

@ -69,8 +69,19 @@ def test_repo_url_definition():
assert _is_app_repo_url("git@github.com:YunoHost-Apps/foobar_ynh.git") assert _is_app_repo_url("git@github.com:YunoHost-Apps/foobar_ynh.git")
assert _is_app_repo_url("https://git.super.host/~max/foobar_ynh") assert _is_app_repo_url("https://git.super.host/~max/foobar_ynh")
### Gitea
assert _is_app_repo_url("https://gitea.instance.tld/user/repo_ynh")
assert _is_app_repo_url("https://gitea.instance.tld/user/repo_ynh/src/branch/branch_name")
assert _is_app_repo_url("https://gitea.instance.tld/user/repo_ynh/src/tag/tag_name")
assert _is_app_repo_url("https://gitea.instance.tld/user/repo_ynh/src/commit/abcd1234")
### Invalid patterns
# no schema
assert not _is_app_repo_url("github.com/YunoHost-Apps/foobar_ynh") assert not _is_app_repo_url("github.com/YunoHost-Apps/foobar_ynh")
# http
assert not _is_app_repo_url("http://github.com/YunoHost-Apps/foobar_ynh") assert not _is_app_repo_url("http://github.com/YunoHost-Apps/foobar_ynh")
# does not end in `_ynh`
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_wat") assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_wat")
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_ynh_wat") assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_ynh_wat")
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar/tree/testing") assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar/tree/testing")

View file

@ -16,6 +16,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import pwd
import re import re
import os import os
import subprocess import subprocess
@ -174,6 +175,12 @@ def tools_postinstall(
raw_msg=True, raw_msg=True,
) )
# Crash early if the username is already a system user, which is
# a common confusion. We don't want to crash later and end up in an half-configured state.
all_existing_usernames = {x.pw_name for x in pwd.getpwall()}
if username in all_existing_usernames:
raise YunohostValidationError("system_username_exists")
if username in ADMIN_ALIASES: if username in ADMIN_ALIASES:
raise YunohostValidationError( raise YunohostValidationError(
f"Unfortunately, {username} cannot be used as a username", raw_msg=True f"Unfortunately, {username} cannot be used as a username", raw_msg=True

View file

@ -22,7 +22,7 @@ import shutil
import random import random
import tempfile import tempfile
import subprocess import subprocess
from typing import Dict, Any, List from typing import Dict, Any, List, Union
from moulinette import m18n from moulinette import m18n
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
@ -1011,16 +1011,16 @@ class AptDependenciesAppResource(AppResource):
##### Example ##### Example
```toml ```toml
[resources.apt] [resources.apt]
packages = "nyancat, lolcat, sl" packages = ["nyancat", "lolcat", "sl"]
# (this part is optional and corresponds to the legacy ynh_install_extra_app_dependencies helper) # (this part is optional and corresponds to the legacy ynh_install_extra_app_dependencies helper)
extras.yarn.repo = "deb https://dl.yarnpkg.com/debian/ stable main" extras.yarn.repo = "deb https://dl.yarnpkg.com/debian/ stable main"
extras.yarn.key = "https://dl.yarnpkg.com/debian/pubkey.gpg" extras.yarn.key = "https://dl.yarnpkg.com/debian/pubkey.gpg"
extras.yarn.packages = "yarn" extras.yarn.packages = ["yarn"]
``` ```
##### Properties ##### Properties
- `packages`: Comma-separated list of packages to be installed via `apt` - `packages`: List of packages to be installed via `apt`
- `packages_from_raw_bash`: A multi-line bash snippet (using triple quotes as open/close) which should echo additional packages to be installed. Meant to be used for packages to be conditionally installed depending on architecture, debian version, install questions, or other logic. - `packages_from_raw_bash`: A multi-line bash snippet (using triple quotes as open/close) which should echo additional packages to be installed. Meant to be used for packages to be conditionally installed depending on architecture, debian version, install questions, or other logic.
- `extras`: A dict of (repo, key, packages) corresponding to "extra" repositories to fetch dependencies from - `extras`: A dict of (repo, key, packages) corresponding to "extra" repositories to fetch dependencies from
@ -1044,20 +1044,14 @@ class AptDependenciesAppResource(AppResource):
packages: List = [] packages: List = []
packages_from_raw_bash: str = "" packages_from_raw_bash: str = ""
extras: Dict[str, Dict[str, str]] = {} extras: Dict[str, Dict[str, Union[str, List]]] = {}
def __init__(self, properties: Dict[str, Any], *args, **kwargs): def __init__(self, properties: Dict[str, Any], *args, **kwargs):
for key, values in properties.get("extras", {}).items():
if not all(
isinstance(values.get(k), str) for k in ["repo", "key", "packages"]
):
raise YunohostError(
"In apt resource in the manifest: 'extras' repo should have the keys 'repo', 'key' and 'packages' defined and be strings",
raw_msg=True,
)
super().__init__(properties, *args, **kwargs) super().__init__(properties, *args, **kwargs)
if isinstance(self.packages, str):
self.packages = [value.strip() for value in self.packages.split(",")]
if self.packages_from_raw_bash: if self.packages_from_raw_bash:
out, err = self.check_output_bash_snippet(self.packages_from_raw_bash) out, err = self.check_output_bash_snippet(self.packages_from_raw_bash)
if err: if err:
@ -1065,17 +1059,32 @@ class AptDependenciesAppResource(AppResource):
"Error while running apt resource packages_from_raw_bash snippet:" "Error while running apt resource packages_from_raw_bash snippet:"
) )
logger.error(err) logger.error(err)
self.packages += ", " + out.replace("\n", ", ") self.packages += out.split("\n")
for key, values in self.extras.items():
if isinstance(values.get("packages"), str):
values["packages"] = [value.strip() for value in values["packages"].split(",")] # type: ignore
if not isinstance(values.get("repo"), str) \
or not isinstance(values.get("key"), str) \
or not isinstance(values.get("packages"), list):
raise YunohostError(
"In apt resource in the manifest: 'extras' repo should have the keys 'repo', 'key' defined as strings and 'packages' defined as list",
raw_msg=True,
)
def provision_or_update(self, context: Dict = {}): def provision_or_update(self, context: Dict = {}):
script = [f"ynh_install_app_dependencies {self.packages}"] script = " ".join(["ynh_install_app_dependencies", *self.packages])
for repo, values in self.extras.items(): for repo, values in self.extras.items():
script += [ script += "\n" + " ".join([
f"ynh_install_extra_app_dependencies --repo='{values['repo']}' --key='{values['key']}' --package='{values['packages']}'" "ynh_install_extra_app_dependencies",
] f"--repo='{values['repo']}'",
f"--key='{values['key']}'",
f"--package='{' '.join(values['packages'])}'"
])
# FIXME : we're feeding the raw value of values['packages'] to the helper .. if we want to be consistent, may they should be comma-separated, though in the majority of cases, only a single package is installed from an extra repo.. # FIXME : we're feeding the raw value of values['packages'] to the helper .. if we want to be consistent, may they should be comma-separated, though in the majority of cases, only a single package is installed from an extra repo..
self._run_script("provision_or_update", "\n".join(script)) self._run_script("provision_or_update", script)
def deprovision(self, context: Dict = {}): def deprovision(self, context: Dict = {}):
self._run_script("deprovision", "ynh_remove_app_dependencies") self._run_script("deprovision", "ynh_remove_app_dependencies")
@ -1166,7 +1175,7 @@ class PortsResource(AppResource):
port_value = self.get_setting(setting_name) port_value = self.get_setting(setting_name)
if not port_value and name != "main": if not port_value and name != "main":
# Automigrate from legacy setting foobar_port (instead of port_foobar) # Automigrate from legacy setting foobar_port (instead of port_foobar)
legacy_setting_name = "{name}_port" legacy_setting_name = f"{name}_port"
port_value = self.get_setting(legacy_setting_name) port_value = self.get_setting(legacy_setting_name)
if port_value: if port_value:
self.set_setting(setting_name, port_value) self.set_setting(setting_name, port_value)