Compare commits

..

85 commits

Author SHA1 Message Date
Alexandre Aubin
a5049a8a13 Update changelog for 11.2.30 2024-08-31 19:30:00 +02:00
Alexandre Aubin
6e84e3532a
Merge pull request #1943 from YunoHost/fix_ynh_restore_everything
Fix ynh_restore_everything
2024-08-31 18:59:47 +02:00
Josué Tille
917cf251fb
Fix ynh_restore_everything 2024-08-31 18:51:16 +02:00
selfhoster1312
8a5f2808a1 Apply shfmt everywhere 2024-08-31 12:22:40 +02:00
68f35831e7 Add maintenante/shfmt.sh for shell script formatting
Thanks @selfhoster1312 <3
2024-08-31 12:22:40 +02:00
b91e9dd8f4 helpersv2.1: Tabs to spaces 2024-08-31 11:01:20 +02:00
38b39ebaea helpersv1: Tabs to spaces 2024-08-31 11:01:20 +02:00
ef17082768 Fix tabs in hooks script 2024-08-31 11:01:20 +02:00
e3ddb1dc4d Fix tabs and indentations in metronome 2024-08-31 11:01:20 +02:00
Alexandre Aubin
5b37936d11
Merge pull request #1940 from selfhoster1312/fix-syntax
Disambiguate subshell (it's not arithmetics!)
2024-08-30 19:10:58 +02:00
selfhoster1312
e82d20aa7b Disambiguate subshell (it's not arithmetics!) 2024-08-30 19:10:35 +02:00
selfhoster1312
aff885e6b7 helpers v2.1: ynh_add_swap and ynh_smart_mktemp 2024-08-30 15:43:50 +02:00
Alexandre Aubin
7a04462ccd
Merge pull request #1939 from selfhoster1312/rename-helper
docs: ynh_install_app_dependencies -> ynh_apt_install_dependencies
2024-08-29 17:47:29 +02:00
selfhoster1312
606e246ec4 docs: ynh_install_app_dependencies -> ynh_apt_install_dependencies 2024-08-29 17:41:41 +02:00
Alexandre Aubin
e3e8b903c7
Merge pull request #1938 from YunoHost/check-patches-dir
2.1 helpers: check if patches dir exists before getting realpath
2024-08-29 00:27:13 +02:00
OniriCorpe
488f563b45 2.1 helpers: check if the patches directory exists before trying to get its realpath 2024-08-28 23:03:57 +02:00
Alexandre Aubin
3d4804be68 Update changelog for 11.2.29 2024-08-27 14:48:10 +02:00
Alexandre Aubin
d4f774ad72 quality: fix typing issue 2024-08-27 14:45:37 +02:00
Alexandre Aubin
d8ab3e68a9
Merge pull request #1933 from yunohost-bot/weblate-yunohost-core
Translations update from Weblate
2024-08-27 14:45:28 +02:00
xabirequejo
71b50549f5 Translated using Weblate (Basque)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-27 13:12:44 +02:00
craftrac
a40874c305 Translated using Weblate (Greek)
Currently translated at 1.1% (9 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/el/
2024-08-27 13:12:44 +02:00
cjdw
9223d30a83 Translated using Weblate (Indonesian)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-27 13:12:44 +02:00
José M
5ad9962757 Translated using Weblate (Galician)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/
2024-08-27 13:12:44 +02:00
ppr
4dfcc13a3f Translated using Weblate (French)
Currently translated at 99.6% (808 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
2024-08-27 13:12:44 +02:00
xabirequejo
e11b61f49e Translated using Weblate (Basque)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-27 13:12:44 +02:00
cjdw
243a34d2d5 Translated using Weblate (Indonesian)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-27 13:12:44 +02:00
José M
ca2572d00b Translated using Weblate (Galician)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/
2024-08-27 13:12:44 +02:00
Alexandre Aubin
518c3bbbe2
Merge pull request #1935 from YunoHost/actions/black
Format Python code with Black
2024-08-27 13:12:40 +02:00
alexAubin
9517b26c63 🎨 Format Python code with Black 2024-08-27 11:11:57 +00:00
Alexandre Aubin
a6785d34bc apps/config panels: move the computation of the actual 'bind' value to core to avoid having an epic python snippets in the bash code.. 2024-08-27 13:11:32 +02:00
Alexandre Aubin
7c79060467 perf: hmmm try to fix race condition in previous cache system ? 2024-08-26 20:52:21 +02:00
Alexandre Aubin
007c13ce42
Merge pull request #1934 from YunoHost/actions/black
Format Python code with Black
2024-08-26 20:21:24 +02:00
alexAubin
2102242a61 🎨 Format Python code with Black 2024-08-26 18:20:38 +00:00
Alexandre Aubin
c409888a4b quality: use _assert_is_installed for consistency instead of if not _is_intalled(app): raise 2024-08-26 20:20:10 +02:00
Alexandre Aubin
c14ebc8be4 perf: add cache for _get_app_settings() 2024-08-26 20:20:02 +02:00
Alexandre Aubin
9b0553580b apps: generalize replacing __INSTALL_DIR__ and __APP__ in config panel 'bind' statement to any setting 2024-08-26 20:16:48 +02:00
Alexandre Aubin
bc2ed45e9d Update changelog for 11.2.28 2024-08-25 13:22:38 +02:00
Alexandre Aubin
a76cd05e87 apps: in apt resource, fix empty string in packages_from_raw_bash breaking dpkg-build 2024-08-25 13:17:12 +02:00
yunohost-bot
eb14e404d6 [CI] Reformat / remove stale translated strings 2024-08-19 01:58:58 +02:00
zamentur
aae24614c4 🎨 Format Python code with Black 2024-08-19 01:58:36 +02:00
Emmanuel Averty
51787a2f8b trigger hooks when adding or removing user into group 2024-08-19 00:56:59 +02:00
Alexandre Aubin
c5953b5420 ci: try to fix the full test not working because i removed the pytest install @_@ 2024-08-18 22:44:27 +02:00
Alexandre Aubin
4afff118e4
Merge pull request #1930 from yunohost-bot/weblate-yunohost-core
Translations update from Weblate
2024-08-18 13:20:48 +02:00
ppr
6113fde48a Translated using Weblate (French)
Currently translated at 99.5% (807 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
2024-08-18 10:54:48 +02:00
xabirequejo
b734e2ea89 Translated using Weblate (Basque)
Currently translated at 100.0% (811 of 811 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-18 10:54:48 +02:00
Alexandre Aubin
0a44d7cea4
Merge pull request #1929 from YunoHost/ci-autofix-translated-strings-dev
[CI] Reformat / remove stale translated strings
2024-08-16 16:19:17 +02:00
yunohost-bot
5d3280c0fd [CI] Reformat / remove stale translated strings 2024-08-16 14:18:35 +00:00
Alexandre Aubin
8dc521a528
Merge pull request #1927 from YunoHost/actions/black
Format Python code with Black
2024-08-16 16:10:13 +02:00
alexAubin
2e70143da2 🎨 Format Python code with Black 2024-08-16 14:09:58 +00:00
Alexandre Aubin
3095496fe9
Merge pull request #1928 from yunohost-bot/weblate-yunohost-core
Translations update from Weblate
2024-08-16 16:09:39 +02:00
xabirequejo
586d1c7f63 Translated using Weblate (Basque)
Currently translated at 100.0% (809 of 809 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-16 16:07:14 +02:00
tituspijean
d63c61e0df
Add diagnoser about rfkill blocking Wi-Fi card (#1841) 2024-08-16 16:07:10 +02:00
Alexandre Aubin
4248b27b26
Merge pull request #1926 from YunoHost/ci-autofix-translated-strings-dev
[CI] Reformat / remove stale translated strings
2024-08-16 01:21:58 +02:00
yunohost-bot
0f662d069c [CI] Reformat / remove stale translated strings 2024-08-15 23:10:02 +00:00
Alexandre Aubin
7ca710685e
Merge pull request #1253 from YunoHost/backup_mx
[enh] Be able to use postfix as a backup ("secondary") MX hosts
2024-08-16 00:55:21 +02:00
Alexandre Aubin
31d10079c7
Merge pull request #1384 from YunoHost/enh-conserver-group-permission-in-sftp
[enh] Tweak umask for SFTP
2024-08-16 00:45:35 +02:00
ljf (zamentur)
980777ebf1 [enh] Conserver group permission 2024-08-16 00:31:59 +02:00
ljf
436826abf9 [enh] Be able to use postfix as a backup mx hosts 2024-08-15 23:44:07 +02:00
Alexandre Aubin
477fa63f46
Merge pull request #1923 from yunohost-bot/weblate-yunohost-core
Translations update from Weblate
2024-08-15 22:22:53 +02:00
xabirequejo
9a6f7dac3b Translated using Weblate (Basque)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-15 21:36:33 +02:00
cjdw
498006cab6 Translated using Weblate (Indonesian)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-15 21:36:33 +02:00
cjdw
2f186b6f7f Translated using Weblate (Indonesian)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-15 21:36:33 +02:00
cjdw
5708776df6 Translated using Weblate (Indonesian)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-15 21:36:33 +02:00
Ivan Davydov
abdbb7efcd Translated using Weblate (Russian)
Currently translated at 40.9% (330 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ru/
2024-08-15 21:36:33 +02:00
xabirequejo
658ef88e47 Translated using Weblate (Basque)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/
2024-08-15 21:36:33 +02:00
Tagadda
4d5cc62540 🎨 Format Python code with Black 2024-08-15 21:36:29 +02:00
Tagada
f88e4cacdf
Merge pull request #1647 from YunoHost/enh_well-known
[enh] exclude .well-known subpaths from conflict checks
2024-08-15 20:50:17 +02:00
Tagada
36b9188aec
Update src/app.py
Co-authored-by: tituspijean <titus+yunohost@pijean.ovh>
2024-08-15 20:41:09 +02:00
Alexandre Aubin
c104dc6449
Merge pull request #1924 from YunoHost/actions/black
Format Python code with Black
2024-08-08 20:38:16 +02:00
alexAubin
938e400865 🎨 Format Python code with Black 2024-08-08 18:36:00 +00:00
Alexandre Aubin
de9980f31e Zblerg 2024-08-08 20:35:36 +02:00
Alexandre Aubin
f02d4a4376 ci: more optimization, lets not install pytest etc because it should already be in the image 2024-08-08 19:47:53 +02:00
Alexandre Aubin
92f4a605b8 ci: do not run on black PR 2024-08-08 19:41:29 +02:00
Alexandre Aubin
df320a44cf ci: ignore boring warning 'Could not identify correctly the dns zone for domain sub.domain.tld' 2024-08-08 19:37:50 +02:00
Alexandre Aubin
6733526bee ci: try skipping diagnosis during upgrade to speed things up a bit? 2024-08-08 19:37:50 +02:00
Alexandre Aubin
d0df3caed4 ci: propagate misc tweaks for CI speedup made on bookworm 2024-08-08 19:37:50 +02:00
Alexandre Aubin
9083a5cc3d ci: ughr ok, dunno what i was thinking, partially revert the previous commit, go to sleep Aleks ffs 2024-08-08 05:39:52 +02:00
Alexandre Aubin
764fe6a7ba ci: smol optimization to avoid installing unecessary pip dependencies? 2024-08-08 05:26:00 +02:00
Alexandre Aubin
200f0272d5 ci: propagate new CI image names 2024-08-08 01:53:58 +02:00
Alexandre Aubin
9915559c40 Update changelog for 11.2.27 2024-08-03 18:42:08 +02:00
Alexandre Aubin
760256f85d
Merge pull request #1922 from yunohost-bot/weblate-yunohost-core
Translations update from Weblate
2024-08-03 18:41:19 +02:00
Ali Çırçır
684c3d9b2c Translated using Weblate (Turkish)
Currently translated at 3.8% (31 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/tr/
2024-08-03 18:37:48 +02:00
cjdw
90c4034908 Translated using Weblate (Indonesian)
Currently translated at 100.0% (805 of 805 strings)

Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/id/
2024-08-03 18:37:48 +02:00
Alexandre Aubin
3deffdbd57 apt resource: fix handling of empty 'packages' list breaking dpkg-deb call 2024-08-03 18:37:40 +02:00
tituspijean
bc30805c7d
[enh] exclude .well-known subpaths from conflict checks 2023-04-17 13:18:10 +02:00
192 changed files with 7286 additions and 7229 deletions

View file

@ -1,10 +1,11 @@
---
stages:
- lint
- build
- install
- test
- bot
- lint
- doc
- translation
default:
tags:
@ -37,12 +38,17 @@ workflow:
- if: $CI_COMMIT_TAG # For tags
- if: $CI_COMMIT_REF_NAME == "ci-format-$CI_DEFAULT_BRANCH" # Ignore black formatting branch created by the CI
when: never
- if: $CI_COMMIT_REF_NAME == "actions/black" # Ignore black formatting branch created by the CI
when: never
- if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" # If it's not the default branch and if it's a push, then do not trigger a build
when: never
- when: always
variables:
YNH_BUILD_DIR: "/ynh-build"
GIT_CLONE_PATH: '$CI_BUILDS_DIR/$CI_COMMIT_SHA/$CI_JOB_ID'
YNH_SOURCE: "https://github.com/yunohost"
YNH_DEBIAN: "bullseye"
YNH_SKIP_DIAGNOSIS_DURING_UPGRADE: "true"
include:
- template: Code-Quality.gitlab-ci.yml

View file

@ -1,53 +0,0 @@
generate-helpers-doc:
stage: bot
image: "before-install"
needs: []
before_script:
- git config --global user.email "yunohost@yunohost.org"
- git config --global user.name "$GITHUB_USER"
script:
- cd doc
- python3 generate_helper_doc.py 2
- python3 generate_helper_doc.py 2.1
- python3 generate_resource_doc.py > resources.md
- python3 generate_configpanel_and_formoptions_doc.py > forms.md
- hub clone https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/doc.git doc_repo
- cp helpers.v2.md doc_repo/pages/06.contribute/10.packaging_apps/20.scripts/10.helpers/packaging_app_scripts_helpers.md
- cp helpers.v2.1.md doc_repo/pages/06.contribute/10.packaging_apps/20.scripts/12.helpers21/packaging_app_scripts_helpers_v21.md
- cp resources.md doc_repo/pages/06.contribute/10.packaging_apps/10.manifest/10.appresources/packaging_app_manifest_resources.md
- cp forms doc_repo/pages/06.contribute/15.dev/03.forms/forms.md
- cd doc_repo
# replace ${CI_COMMIT_REF_NAME} with ${CI_COMMIT_TAG} ?
- hub checkout -b "${CI_COMMIT_REF_NAME}"
- hub commit -am "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}" -p # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
artifacts:
paths:
- doc/helpers.md
- doc/resources.md
only:
- tags
autofix-translated-strings:
stage: bot
image: "before-install"
needs: []
before_script:
- git config --global user.email "yunohost@yunohost.org"
- 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
- cd github_repo
script:
# create a local branch that will overwrite distant one
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
- python3 maintenance/missing_i18n_keys.py --fix
- python3 maintenance/autofix_locale_format.py
- '[ $(git diff --ignore-blank-lines --ignore-all-space --ignore-space-at-eol --ignore-cr-at-eol | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Reformat / remove stale translated strings" || true
- git push -f origin "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:$CI_COMMIT_REF_NAME -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only:
variables:
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
changes:
- locales/*

View file

@ -1,27 +1,19 @@
.build-stage:
stage: build
needs:
- job: actionsmap
- job: invalidcode311
image: "before-install"
image: "build-and-lint"
variables:
YNH_SOURCE: "https://github.com/yunohost"
YNH_DEBIAN: "bookworm"
YNH_BUILD_DIR: "$GIT_CLONE_PATH/build"
before_script:
- mkdir -p $YNH_BUILD_DIR
- DEBIAN_FRONTEND=noninteractive apt update
artifacts:
paths:
- ./*.deb
.build_script: &build_script
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" install devscripts --no-install-recommends
- cd $YNH_BUILD_DIR/$PACKAGE
- git status || true
- git log -n 1 || true
- VERSION=$(dpkg-parsechangelog -S Version 2>/dev/null)
- VERSION_NIGHTLY="${VERSION}+$(date +%Y%m%d%H%M)"
- dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_NIGHTLY}" -D "unstable" --force-distribution "Daily build."
- VERSION_TIMESTAMPED="${VERSION}+$(date +%Y%m%d%H%M)"
- dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_TIMESTAMPED}" -D "unstable" --force-distribution "CI build."
- debuild --no-lintian -us -uc
- cp $YNH_BUILD_DIR/*.deb ${CI_PROJECT_DIR}/
- cd ${CI_PROJECT_DIR}

View file

@ -0,0 +1,31 @@
########################################
# DOC
########################################
generate-helpers-doc:
stage: doc
image: "build-and-lint"
needs: []
before_script:
- git config --global user.email "yunohost@yunohost.org"
- git config --global user.name "$GITHUB_USER"
script:
- cd doc
- python3 generate_helper_doc.py 2
- python3 generate_helper_doc.py 2.1
- python3 generate_resource_doc.py > resources.md
- hub clone https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/doc.git doc_repo
- cp helpers.v2.md doc_repo/pages/06.contribute/10.packaging_apps/20.scripts/10.helpers/packaging_app_scripts_helpers.md
- cp helpers.v2.1.md doc_repo/pages/06.contribute/10.packaging_apps/20.scripts/12.helpers21/packaging_app_scripts_helpers_v21.md
- cp resources.md doc_repo/pages/06.contribute/10.packaging_apps/10.manifest/10.appresources/packaging_app_manifest_resources.md
- cd doc_repo
# replace ${CI_COMMIT_REF_NAME} with ${CI_COMMIT_TAG} ?
- hub checkout -b "${CI_COMMIT_REF_NAME}"
- hub commit -am "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}" -p # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
artifacts:
paths:
- doc/helpers.md
- doc/resources.md
only:
- tags

View file

@ -14,20 +14,14 @@
upgrade:
extends: .install-stage
image: "after-install"
image: "core-tests"
script:
- apt-get update -o Acquire::Retries=3
- systemctl restart nginx || journalctl -u nginx -n 50 --no-pager --no-hostname
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
- systemctl restart nginx || journalctl -u nginx -n 50 --no-pager --no-hostname
install-postinstall:
extends: .install-stage
image: "before-install"
script:
- apt-get update -o Acquire::Retries=3
- systemctl restart nginx || journalctl -u nginx -n 50 --no-pager --no-hostname
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
- systemctl restart nginx || journalctl -u nginx -n 50 --no-pager --no-hostname
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace

View file

@ -3,38 +3,24 @@
########################################
# later we must fix lint and format-check jobs and remove "allow_failure"
actionsmap:
lint39:
stage: lint
image: "before-install"
needs: []
script:
- python -c 'import yaml; yaml.safe_load(open("share/actionsmap.yml"))'
- python -c 'import yaml; yaml.safe_load(open("share/actionsmap-portal.yml"))'
lint311:
stage: lint
image: "before-install"
image: "build-and-lint"
needs: []
allow_failure: true
script:
- tox -e py311-lint
- tox -e py39-lint
invalidcode311:
invalidcode39:
stage: lint
image: "before-install"
image: "build-and-lint"
needs: []
script:
- tox -e py311-invalidcode
- tox -e py39-invalidcode
mypy:
stage: lint
image: "before-install"
image: "build-and-lint"
needs: []
script:
- tox -e py311-mypy
i18n-keys:
stage: lint
needs: []
script:
- python3 maintenance/missing_i18n_keys.py --check
- tox -e py39-mypy

View file

@ -1,10 +1,9 @@
.install_debs: &install_debs
- 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
.test-stage:
stage: test
image: "after-install"
image: "core-tests"
variables:
PYTEST_ADDOPTS: "--color=yes"
before_script:
@ -26,27 +25,36 @@
# TESTS
########################################
#full-tests:
# stage: test
# image: "before-install"
# variables:
# PYTEST_ADDOPTS: "--color=yes"
# before_script:
# - *install_debs
# - yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace
# script:
# - python3 -m pytest --cov=yunohost tests/ src/tests/ --junitxml=report.xml
# needs:
# - job: build-yunohost
# artifacts: true
# - job: build-ssowat
# artifacts: true
# - job: build-moulinette
# artifacts: true
# coverage: '/TOTAL.*\s+(\d+%)/'
# artifacts:
# reports:
# junit: report.xml
full-tests:
stage: test
image: "before-install"
variables:
PYTEST_ADDOPTS: "--color=yes"
before_script:
- *install_debs
- pip install mock pip pyOpenSSL pytest pytest-cov pytest-mock pytest-sugar requests-mock "packaging<22"
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace
script:
- python3 -m pytest --cov=yunohost tests/ src/tests/ --junitxml=report.xml
needs:
- job: build-yunohost
artifacts: true
- job: build-ssowat
artifacts: true
- job: build-moulinette
artifacts: true
coverage: '/TOTAL.*\s+(\d+%)/'
artifacts:
reports:
junit: report.xml
test-actionmap:
extends: .test-stage
script:
- python3 -m pytest tests/test_actionmap.py
only:
changes:
- share/actionsmap.yml
test-helpers2:
extends: .test-stage
@ -64,134 +72,129 @@ test-domains:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_domains.py
# only:
# changes:
# - src/domain.py
only:
changes:
- src/domain.py
test-dns:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_dns.py
# only:
# changes:
# - src/dns.py
# - src/utils/dns.py
only:
changes:
- src/dns.py
- src/utils/dns.py
test-apps:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_apps.py
# only:
# changes:
# - src/app.py
only:
changes:
- src/app.py
test-appscatalog:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_app_catalog.py
# only:
# changes:
# - src/app_calalog.py
only:
changes:
- src/app_calalog.py
test-appurl:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_appurl.py
# only:
# changes:
# - src/app.py
only:
changes:
- src/app.py
test-questions:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_questions.py
# only:
# changes:
# - src/utils/config.py
only:
changes:
- src/utils/config.py
test-app-config:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_app_config.py
# only:
# changes:
# - src/app.py
# - src/utils/config.py
only:
changes:
- src/app.py
- src/utils/config.py
test-app-resources:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_app_resources.py
# only:
# changes:
# - src/app.py
# - src/utils/resources.py
only:
changes:
- src/app.py
- src/utils/resources.py
test-changeurl:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_changeurl.py
# only:
# changes:
# - src/app.py
only:
changes:
- src/app.py
test-backuprestore:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_backuprestore.py
# only:
# changes:
# - src/backup.py
only:
changes:
- src/backup.py
test-permission:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_permission.py
# only:
# changes:
# - src/permission.py
only:
changes:
- src/permission.py
test-settings:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_settings.py
# only:
# changes:
# - src/settings.py
only:
changes:
- src/settings.py
test-user-group:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_user-group.py
# only:
# changes:
# - src/user.py
only:
changes:
- src/user.py
test-regenconf:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_regenconf.py
# only:
# changes:
# - src/regenconf.py
only:
changes:
- src/regenconf.py
test-service:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_service.py
# only:
# changes:
# - src/service.py
only:
changes:
- src/service.py
test-ldapauth:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_ldapauth.py
# only:
# changes:
# - src/authenticators/*.py
test-sso-and-portalapi:
extends: .test-stage
script:
- python3 -m pytest src/tests/test_sso_and_portalapi.py
only:
changes:
- src/authenticators/*.py

View file

@ -0,0 +1,36 @@
########################################
# TRANSLATION
########################################
test-i18n-keys:
stage: translation
script:
- python3 maintenance/missing_i18n_keys.py --check
only:
changes:
- locales/en.json
- src/*.py
- src/diagnosers/*.py
autofix-translated-strings:
stage: translation
image: "build-and-lint"
needs: []
before_script:
- git config --global user.email "yunohost@yunohost.org"
- 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
- cd github_repo
script:
# create a local branch that will overwrite distant one
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
- python3 maintenance/missing_i18n_keys.py --fix
- python3 maintenance/autofix_locale_format.py
- '[ $(git diff --ignore-blank-lines --ignore-all-space --ignore-space-at-eol --ignore-cr-at-eol | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Reformat / remove stale translated strings" || true
- git push -f origin "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:$CI_COMMIT_REF_NAME -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only:
variables:
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
changes:
- locales/*

View file

@ -1,53 +0,0 @@
#! /usr/bin/python3
# -*- coding: utf-8 -*-
import argparse
import yunohost
# Default server configuration
DEFAULT_HOST = "localhost"
DEFAULT_PORT = 6788
def _parse_api_args():
"""Parse main arguments for the api"""
parser = argparse.ArgumentParser(
add_help=False,
description="Run the YunoHost API to manage your server.",
)
srv_group = parser.add_argument_group("server configuration")
srv_group.add_argument(
"-h",
"--host",
action="store",
default=DEFAULT_HOST,
help="Host to listen on (default: %s)" % DEFAULT_HOST,
)
srv_group.add_argument(
"-p",
"--port",
action="store",
default=DEFAULT_PORT,
type=int,
help="Port to listen on (default: %d)" % DEFAULT_PORT,
)
glob_group = parser.add_argument_group("global arguments")
glob_group.add_argument(
"--debug",
action="store_true",
default=False,
help="Set log level to DEBUG",
)
glob_group.add_argument(
"--help",
action="help",
help="Show this help message and exit",
)
return parser.parse_args()
if __name__ == "__main__":
opts = _parse_api_args()
# Run the server
yunohost.portalapi(debug=opts.debug, host=opts.host, port=opts.port)

View file

@ -132,8 +132,12 @@ def main() -> bool:
)
continue
# Broadcast IPv4 and IPv6
ips: List[str] = interfaces[interface]["ipv4"] + interfaces[interface]["ipv6"]
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
# Buster only ships 0.1.6
# 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 not ips:

View file

@ -1,9 +1,13 @@
{% set interfaces_list = interfaces.split(' ') %}
{% for interface in interfaces_list %}
interface-name={{ domain }},{{ interface }}
interface-name=xmpp-upload.{{ domain }},{{ interface }}
{% endfor %}
{% if ipv6 %}
host-record={{ domain }},{{ ipv6 }}
host-record=xmpp-upload.{{ domain }},{{ ipv6 }}
{% endif %}
txt-record={{ domain }},"v=spf1 mx a -all"
mx-host={{ domain }},{{ domain }},5
srv-host=_xmpp-client._tcp.{{ domain }},{{ domain }},5222,0,5
srv-host=_xmpp-server._tcp.{{ domain }},{{ domain }},5269,0,5

View file

@ -13,8 +13,9 @@ protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %}
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
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.19&config=intermediate&openssl=3.0.9&guideline=5.7
# 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.4&config=intermediate&openssl=1.1.1d&guideline=5.6
ssl = required
@ -31,7 +32,7 @@ ssl_dh = </usr/share/yunohost/ffdhe2048.pem
# intermediate configuration
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:DHE-RSA-CHACHA20-POLY1305
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_prefer_server_ciphers = no
###############################################################################
@ -141,6 +142,18 @@ plugin {
sieve_before = /etc/dovecot/global_script/
}
plugin {
antispam_debug_target = syslog
antispam_verbose_debug = 0
antispam_backend = pipe
antispam_spam_pattern_ignorecase = junk;spam
antispam_trash_pattern_ignorecase = trash;papierkorb;deleted messages
antispam_pipe_program = /usr/bin/rspamc
antispam_pipe_program_args = -h;localhost:11334;-P;q1
antispam_pipe_program_spam_arg = learn_spam
antispam_pipe_program_notspam_arg = learn_ham
}
plugin {
quota = maildir:User quota
quota_rule2 = SPAM:ignore

View file

@ -18,7 +18,7 @@
# See man 5 jail.conf for details.
#
# [DEFAULT]
# bantime = 1h
# bantime = 3600
#
# [sshd]
# enabled = true
@ -44,52 +44,10 @@ before = paths-debian.conf
# MISCELLANEOUS OPTIONS
#
# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
#bantime.increment = true
# "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
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. 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
# 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.
@ -98,18 +56,15 @@ before = paths-debian.conf
ignorecommand =
# "bantime" is the number of seconds that a host is banned.
bantime = 10m
bantime = 600
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime = 10m
findtime = 600
# "maxretry" is the number of failures before a host get banned.
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.
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
# This option can be overridden in each jail as well.
@ -158,13 +113,10 @@ logencoding = auto
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.
# By default jails have names matching their filter name
#
filter = %(__name__)s[mode=%(mode)s]
filter = %(__name__)s
#
@ -188,7 +140,7 @@ mta = sendmail
# Default protocol
protocol = tcp
# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
# Specify chain where jumps would need to be added in iptables-* actions
chain = INPUT
# Ports to be banned
@ -209,53 +161,51 @@ banaction = iptables-multiport
banaction_allports = iptables-allports
# The simplest action to take: ban only
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report to the destemail.
action_mw = %(action_)s
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(action_)s
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, 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
#
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
# to the destemail.
action_xarf = %(action_)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
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
# to the destemail.
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
# Report block via blocklist.de fail2ban reporting service API
#
# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in
# corresponding jail.d/my-jail.local file).
# See the IMPORTANT note in action.d/blocklist_de.conf for when to
# use this action. Create a file jail.d/blocklist_de.local containing
# [Init]
# blocklist_de_apikey = {api key from registration]
#
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
# Report ban via abuseipdb.com.
# Report ban via badips.com, and use as blacklist
#
# See action.d/abuseipdb.conf for usage example and details.
# See BadIPsAction docstring in config/action.d/badips.py for
# documentation for this action.
#
action_abuseipdb = abuseipdb
# NOTE: This action relies on banaction being present on start and therefore
# 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
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
@ -273,10 +223,15 @@ action = %(action_)s
[sshd]
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode = normal
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
[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
logpath = %(sshd_log)s
backend = %(sshd_backend)s
@ -310,7 +265,7 @@ logpath = %(apache_error_log)s
# for email addresses. The mail outputs are buffered.
port = http,https
logpath = %(apache_access_log)s
bantime = 48h
bantime = 172800
maxretry = 1
@ -346,7 +301,7 @@ maxretry = 2
port = http,https
logpath = %(apache_access_log)s
maxretry = 1
ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot <ip>
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
[apache-modsecurity]
@ -366,15 +321,12 @@ maxretry = 1
[openhab-auth]
filter = openhab
banaction = %(banaction_allports)s
action = iptables-allports[name=NoAuthFailures]
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]
# mode = normal
port = http,https
logpath = %(nginx_error_log)s
@ -390,10 +342,8 @@ logpath = %(nginx_error_log)s
port = http,https
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
# through GET/POST variables. - Experimental, with more than a year
@ -427,8 +377,6 @@ logpath = %(lighttpd_error_log)s
port = http,https
logpath = %(roundcube_errors_log)s
# Use following line in your jail.local if roundcube logs to journal.
#backend = %(syslog_backend)s
[openwebmail]
@ -478,13 +426,11 @@ backend = %(syslog_backend)s
port = http,https
logpath = /var/log/tomcat*/catalina.out
#logpath = /var/log/guacamole.log
[monit]
#Ban clients brute-forcing the monit gui login
port = 2812
logpath = /var/log/monit
/var/log/monit.log
[webmin-auth]
@ -567,29 +513,27 @@ logpath = %(vsftpd_log)s
# ASSP SMTP Proxy Jail
[assp]
port = smtp,465,submission
port = smtp,submission
logpath = /root/path/to/assp/logs/maillog.txt
[courier-smtp]
port = smtp,465,submission
port = smtp,submission
logpath = %(syslog_mail)s
backend = %(syslog_backend)s
[postfix]
# To use another modes set filter parameter "mode" in jail.local:
mode = more
port = smtp,465,submission
port = smtp,submission
logpath = %(postfix_log)s
backend = %(postfix_backend)s
[postfix-rbl]
filter = postfix[mode=rbl]
port = smtp,465,submission
port = smtp,submission
logpath = %(postfix_log)s
backend = %(postfix_backend)s
maxretry = 1
@ -597,17 +541,14 @@ maxretry = 1
[sendmail-auth]
port = submission,465,smtp
port = submission,smtp
logpath = %(syslog_mail)s
backend = %(syslog_backend)s
[sendmail-reject]
# To use more aggressive modes set filter parameter "mode" in jail.local:
# 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
port = smtp,submission
logpath = %(syslog_mail)s
backend = %(syslog_backend)s
@ -615,7 +556,7 @@ backend = %(syslog_backend)s
[qmail-rbl]
filter = qmail
port = smtp,465,submission
port = smtp,submission
logpath = /service/qmail/log/main/current
@ -623,14 +564,14 @@ logpath = /service/qmail/log/main/current
# but can be set by syslog_facility in the dovecot configuration.
[dovecot]
port = pop3,pop3s,imap,imaps,submission,465,sieve
port = pop3,pop3s,imap,imaps,submission,sieve
logpath = %(dovecot_log)s
backend = %(dovecot_backend)s
[sieve]
port = smtp,465,submission
port = smtp,submission
logpath = %(dovecot_log)s
backend = %(dovecot_backend)s
@ -642,21 +583,20 @@ logpath = %(solidpop3d_log)s
[exim]
# see filter.d/exim.conf for further modes supported from filter:
#mode = normal
port = smtp,465,submission
port = smtp,submission
logpath = %(exim_main_log)s
[exim-spam]
port = smtp,465,submission
port = smtp,submission
logpath = %(exim_main_log)s
[kerio]
port = imap,smtp,imaps,465
port = imap,smtp,imaps
logpath = /opt/kerio/mailserver/store/logs/security.log
@ -667,15 +607,14 @@ logpath = /opt/kerio/mailserver/store/logs/security.log
[courier-auth]
port = smtp,465,submission,imap,imaps,pop3,pop3s
port = smtp,submission,imaps,pop3,pop3s
logpath = %(syslog_mail)s
backend = %(syslog_backend)s
[postfix-sasl]
filter = postfix[mode=auth]
port = smtp,465,submission,imap,imaps,pop3,pop3s
port = smtp,submission,imap,imaps,pop3,pop3s
# You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize.
@ -692,7 +631,7 @@ backend = %(syslog_backend)s
[squirrelmail]
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
port = smtp,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
@ -745,8 +684,8 @@ logpath = /var/log/named/security.log
[nsd]
port = 53
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
logpath = /var/log/nsd.log
@ -757,8 +696,9 @@ logpath = /var/log/nsd.log
[asterisk]
port = 5060,5061
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
logpath = /var/log/asterisk/messages
maxretry = 10
@ -766,22 +706,16 @@ maxretry = 10
[freeswitch]
port = 5060,5061
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
logpath = /var/log/freeswitch.log
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
# equivalent section:
# log-warnings = 2
# log-warning = 2
#
# for syslog (daemon facility)
# [mysqld_safe]
@ -797,14 +731,6 @@ logpath = %(mysql_log)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')
[mongodb-auth]
# change port when running with "--shardsvr" or "--configsvr" runtime operation
@ -823,8 +749,8 @@ logpath = /var/log/mongodb/mongodb.log
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime = 1w
findtime = 1d
bantime = 604800 ; 1 week
findtime = 86400 ; 1 day
# Generic filter for PAM. Has to be used with action which bans all
@ -860,31 +786,11 @@ logpath = /var/log/ejabberd/ejabberd.log
[counter-strike]
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
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
%(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
action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
%(banaction)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
# consider low maxretry and a long bantime
# nobody except your own Nagios server should ever probe nrpe
@ -918,9 +824,7 @@ filter = apache-pass[knocking_url="%(knocking_url)s"]
logpath = %(apache_access_log)s
blocktype = RETURN
returntype = DROP
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
actionstart_on_demand=false, actionrepair_on_unban=true]
bantime = 1h
bantime = 3600
maxretry = 1
findtime = 1
@ -928,8 +832,8 @@ findtime = 1
[murmur]
# AKA mumble-server
port = 64738
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol=tcp, chain="%(chain)s", actname=%(banaction)s-tcp]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol=udp, chain="%(chain)s", actname=%(banaction)s-udp]
logpath = /var/log/mumble-server/mumble-server.log
@ -947,34 +851,5 @@ logpath = /var/log/haproxy.log
[slapd]
port = ldap,ldaps
filter = slapd
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

View file

@ -31,12 +31,3 @@ protocol = tcp
filter = yunohost
logpath = /var/log/nginx/*error.log
/var/log/nginx/*access.log
[yunohost-portal]
enabled = true
port = http,https
protocol = tcp
filter = yunohost-portal
logpath = /var/log/nginx/*error.log
/var/log/nginx/*access.log
maxretry = 20

View file

@ -1,3 +0,0 @@
[Definition]
failregex = ^<HOST> -.*\"POST /yunohost/portalapi/login HTTP/\d.\d\" 401
ignoreregex =

View file

@ -1,3 +1,24 @@
# Fail2Ban configuration file
#
# Author: Adrien Beudin
#
# $Revision: 2 $
#
[Definition]
failregex = ^<HOST> -.*\"POST /yunohost/api/login HTTP/\d.\d\" 401
# Option: failregex
# Notes.: regex to match the password failure messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values: TEXT
#
failregex = helpers.lua:[0-9]+: authenticate\(\): Connection failed for: .*, client: <HOST>
^<HOST> -.*\"POST /yunohost/api/login HTTP/\d.\d\" 401
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

View file

@ -0,0 +1,75 @@
VirtualHost "{{ domain }}"
enable = true
ssl = {
key = "/etc/yunohost/certs/{{ domain }}/key.pem";
certificate = "/etc/yunohost/certs/{{ domain }}/crt.pem";
}
authentication = "ldap2"
ldap = {
hostname = "localhost",
user = {
basedn = "ou=users,dc=yunohost,dc=org",
filter = "(&(objectClass=posixAccount)(mail=*@{{ domain }})(permission=cn=xmpp.main,ou=permission,dc=yunohost,dc=org))",
usernamefield = "mail",
namefield = "cn",
},
}
-- Discovery items
disco_items = {
{ "muc.{{ domain }}" },
{ "pubsub.{{ domain }}" },
{ "jabber.{{ domain }}" },
{ "vjud.{{ domain }}" },
{ "xmpp-upload.{{ domain }}" },
};
-- contact_info = {
-- abuse = { "mailto:abuse@{{ domain }}", "xmpp:admin@{{ domain }}" };
-- admin = { "mailto:root@{{ domain }}", "xmpp:admin@{{ domain }}" };
-- };
------ Components ------
-- You can specify components to add hosts that provide special services,
-- like multi-user conferences, and transports.
---Set up a MUC (multi-user chat) room server
Component "muc.{{ domain }}" "muc"
name = "{{ domain }} Chatrooms"
modules_enabled = {
"muc_limits";
"muc_log";
"muc_log_mam";
"muc_log_http";
"muc_vcard";
}
muc_event_rate = 0.5
muc_burst_factor = 10
room_default_config = {
logging = true,
persistent = true
};
---Set up a PubSub server
Component "pubsub.{{ domain }}" "pubsub"
name = "{{ domain }} Publish/Subscribe"
unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server)
---Set up a HTTP Upload service
Component "xmpp-upload.{{ domain }}" "http_upload"
name = "{{ domain }} Sharing Service"
http_file_path = "/var/xmpp-upload/{{ domain }}/upload"
http_external_url = "https://xmpp-upload.{{ domain }}:443"
http_file_base_path = "/upload"
http_file_size_limit = 6*1024*1024
http_file_quota = 60*1024*1024
http_upload_file_size_limit = 100 * 1024 * 1024 -- bytes
http_upload_quota = 10 * 1024 * 1024 * 1024 -- bytes
---Set up a VJUD service
Component "vjud.{{ domain }}" "vjud"
vjud_disco_name = "{{ domain }} User Directory"

View file

@ -0,0 +1,123 @@
-- ** Metronome's config file example **
--
-- The format is exactly equal to Prosody's:
--
-- Lists are written { "like", "this", "one" }
-- Lists can also be of { 1, 2, 3 } numbers, etc.
-- Either commas, or semi-colons; may be used as seperators.
--
-- A table is a list of values, except each value has a name. An
-- example would be:
--
-- ssl = { key = "keyfile.key", certificate = "certificate.cert" }
--
-- Tip: You can check that the syntax of this file is correct when you have finished
-- by running: luac -p metronome.cfg.lua
-- If there are any errors, it will let you know what and where they are, otherwise it
-- will keep quiet.
-- Global settings go in this section
-- This is the list of modules Metronome will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
modules_enabled = {
-- Generally required
"roster"; -- Allow users to have a roster. Recommended.
"saslauth"; -- Authentication for clients. Recommended if you want to log in.
"tls"; -- Add support for secure TLS on c2s/s2s connections
"disco"; -- Service discovery
-- Not essential, but recommended
"private"; -- Private XML storage (for room bookmarks, etc.)
"vcard"; -- Allow users to set vCards
"pep"; -- Allows setting of mood, tune, etc.
"pubsub"; -- Publish-subscribe XEP-0060
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
"bidi"; -- Enables Bidirectional Server-to-Server Streams.
-- Nice to have
"version"; -- Replies to server version requests
"uptime"; -- Report how long server has been running
"time"; -- Let others know the time here on this server
"ping"; -- Replies to XMPP pings with pongs
"register"; -- Allow users to register on this server using a client and change passwords
"stream_management"; -- Allows clients and servers to use Stream Management
"stanza_optimizations"; -- Allows clients to use Client State Indication and SIFT
"message_carbons"; -- Allows clients to enable carbon copies of messages
"mam"; -- Enable server-side message archives using Message Archive Management
"push"; -- Enable Push Notifications via PubSub using XEP-0357
"lastactivity"; -- Enables clients to know the last presence status of an user
"adhoc_cm"; -- Allow to set client certificates to login through SASL External via adhoc
"admin_adhoc"; -- administration adhoc commands
"bookmarks"; -- XEP-0048 Bookmarks synchronization between PEP and Private Storage
"sec_labels"; -- Allows to use a simplified version XEP-0258 Security Labels and related ACDFs.
"privacy"; -- Add privacy lists and simple blocking command support
-- Other specific functionality
--"admin_telnet"; -- administration console, telnet to port 5582
--"admin_web"; -- administration web interface
"bosh"; -- Enable support for BOSH clients, aka "XMPP over Bidirectional Streams over Synchronous HTTP"
--"compression"; -- Allow clients to enable Stream Compression
--"spim_block"; -- Require authorization via OOB form for messages from non-contacts and block unsollicited messages
--"gate_guard"; -- Enable config-based blacklisting and hit-based auto-banning features
--"incidents_handling"; -- Enable Incidents Handling support (can be administered via adhoc commands)
--"server_presence"; -- Enables Server Buddies extension support
--"service_directory"; -- Enables Service Directories extension support
--"public_service"; -- Enables Server vCard support for public services in directories and advertises in features
--"register_api"; -- Provides secure API for both Out-Of-Band and In-Band registration for E-Mail verification
"websocket"; -- Enable support for WebSocket clients, aka "XMPP over WebSockets"
};
-- Server PID
pidfile = "/var/run/metronome/metronome.pid"
-- HTTP server
http_ports = { 5290 }
http_interfaces = { "127.0.0.1", "::1" }
--https_ports = { 5291 }
--https_interfaces = { "127.0.0.1", "::1" }
-- Enable IPv6
use_ipv6 = true
-- BOSH configuration (mod_bosh)
consider_bosh_secure = true
cross_domain_bosh = true
-- WebSocket configuration (mod_websocket)
consider_websocket_secure = true
cross_domain_websocket = true
-- Disable account creation by default, for security
allow_registration = false
-- Use LDAP storage backend for all stores
storage = "ldap"
-- stanza optimization
csi_config_queue_all_muc_messages_but_mentions = false;
-- Logging configuration
log = {
info = "/var/log/metronome/metronome.log"; -- Change 'info' to 'debug' for verbose logging
error = "/var/log/metronome/metronome.err";
-- "*syslog"; -- Uncomment this for logging to syslog
-- "*console"; -- Log to the console, useful for debugging with daemonize=false
}
------ Components ------
-- You can specify components to add hosts that provide special services,
-- like multi-user conferences, and transports.
---Set up a local BOSH service
Component "localhost" "http"
modules_enabled = { "bosh" }
----------- Virtual hosts -----------
-- You need to add a VirtualHost entry for each domain you wish Metronome to serve.
-- Settings under each VirtualHost entry apply *only* to that host.
Include "conf.d/*.cfg.lua"

View file

@ -0,0 +1,270 @@
-- vim:sts=4 sw=4
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2012 Rob Hoelz
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local ldap;
local connection;
local params = module:get_option("ldap");
local format = string.format;
local tconcat = table.concat;
local _M = {};
local config_params = {
hostname = 'string',
user = {
basedn = 'string',
namefield = 'string',
filter = 'string',
usernamefield = 'string',
},
groups = {
basedn = 'string',
namefield = 'string',
memberfield = 'string',
_member = {
name = 'string',
admin = 'boolean?',
},
},
admin = {
_optional = true,
basedn = 'string',
namefield = 'string',
filter = 'string',
}
}
local function run_validation(params, config, prefix)
prefix = prefix or '';
-- verify that every required member of config is present in params
for k, v in pairs(config) do
if type(k) == 'string' and k:sub(1, 1) ~= '_' then
local is_optional;
if type(v) == 'table' then
is_optional = v._optional;
else
is_optional = v:sub(-1) == '?';
end
if not is_optional and params[k] == nil then
return nil, prefix .. k .. ' is required';
end
end
end
for k, v in pairs(params) do
local expected_type = config[k];
local ok, err = true;
if type(k) == 'string' then
-- verify that this key is present in config
if k:sub(1, 1) == '_' or expected_type == nil then
return nil, 'invalid parameter ' .. prefix .. k;
end
-- type validation
if type(expected_type) == 'string' then
if expected_type:sub(-1) == '?' then
expected_type = expected_type:sub(1, -2);
end
if type(v) ~= expected_type then
return nil, 'invalid type for parameter ' .. prefix .. k;
end
else -- it's a table (or had better be)
if type(v) ~= 'table' then
return nil, 'invalid type for parameter ' .. prefix .. k;
end
-- recurse into child
ok, err = run_validation(v, expected_type, prefix .. k .. '.');
end
else -- it's an integer (or had better be)
if not config._member then
return nil, 'invalid parameter ' .. prefix .. tostring(k);
end
ok, err = run_validation(v, config._member, prefix .. tostring(k) .. '.');
end
if not ok then
return ok, err;
end
end
return true;
end
local function validate_config()
if true then
return true; -- XXX for now
end
-- this is almost too clever (I mean that in a bad
-- maintainability sort of way)
--
-- basically this allows a free pass for a key in group members
-- equal to params.groups.namefield
setmetatable(config_params.groups._member, {
__index = function(_, k)
if k == params.groups.namefield then
return 'string';
end
end
});
local ok, err = run_validation(params, config_params);
setmetatable(config_params.groups._member, nil);
if ok then
-- a little extra validation that doesn't fit into
-- my recursive checker
local group_namefield = params.groups.namefield;
for i, group in ipairs(params.groups) do
if not group[group_namefield] then
return nil, format('groups.%d.%s is required', i, group_namefield);
end
end
-- fill in params.admin if you can
if not params.admin and params.groups then
local admingroup;
for _, groupconfig in ipairs(params.groups) do
if groupconfig.admin then
admingroup = groupconfig;
break;
end
end
if admingroup then
params.admin = {
basedn = params.groups.basedn,
namefield = params.groups.memberfield,
filter = group_namefield .. '=' .. admingroup[group_namefield],
};
end
end
end
return ok, err;
end
-- what to do if connection isn't available?
local function connect()
return ldap.open_simple(params.hostname, params.bind_dn, params.bind_password, params.use_tls);
end
-- this is abstracted so we can maintain persistent connections at a later time
function _M.getconnection()
return connect();
end
function _M.getparams()
return params;
end
-- XXX consider renaming this...it doesn't bind the current connection
function _M.bind(username, password)
local conn = _M.getconnection();
local filter = format('%s=%s', params.user.usernamefield, username);
if params.user.usernamefield == 'mail' then
filter = format('mail=%s@*', username);
end
if filter then
filter = _M.filter.combine_and(filter, params.user.filter);
end
local who = _M.singlematch {
attrs = params.user.usernamefield,
base = params.user.basedn,
filter = filter,
};
if who then
who = who.dn;
module:log('debug', '_M.bind - who: %s', who);
else
module:log('debug', '_M.bind - no DN found for username = %s', username);
return nil, format('no DN found for username = %s', username);
end
local conn, err = ldap.open_simple(params.hostname, who, password, params.use_tls);
if conn then
conn:close();
return true;
end
return conn, err;
end
function _M.singlematch(query)
local ld = _M.getconnection();
query.sizelimit = 1;
query.scope = 'subtree';
for dn, attribs in ld:search(query) do
attribs.dn = dn;
return attribs;
end
end
_M.filter = {};
function _M.filter.combine_and(...)
local parts = { '(&' };
local arg = { ... };
for _, filter in ipairs(arg) do
if filter:sub(1, 1) ~= '(' and filter:sub(-1) ~= ')' then
filter = '(' .. filter .. ')'
end
parts[#parts + 1] = filter;
end
parts[#parts + 1] = ')';
return tconcat(parts, '');
end
do
local ok, err;
metronome.unlock_globals();
ok, ldap = pcall(require, 'lualdap');
metronome.lock_globals();
if not ok then
module:log("error", "Failed to load the LuaLDAP library for accessing LDAP: %s", ldap);
module:log("error", "More information on install LuaLDAP can be found at http://www.keplerproject.org/lualdap");
return;
end
if not params then
module:log("error", "LDAP configuration required to use the LDAP storage module");
return;
end
ok, err = validate_config();
if not ok then
module:log("error", "LDAP configuration is invalid: %s", tostring(err));
return;
end
end
return _M;

View file

@ -0,0 +1,90 @@
-- vim:sts=4 sw=4
-- Metronome IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2012 Rob Hoelz
-- Copyright (C) 2015 YUNOHOST.ORG
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
-- https://github.com/YunoHost/yunohost-config-metronome/blob/unstable/lib/modules/mod_auth_ldap2.lua
-- adapted to use common LDAP store on Metronome
local ldap = module:require 'ldap';
local new_sasl = require 'util.sasl'.new;
local jsplit = require 'util.jid'.split;
local log = module._log
if not ldap then
return;
end
function new_default_provider(host)
local provider = { name = "ldap2" };
log("debug", "initializing ldap2 authentication provider for host '%s'", host);
function provider.test_password(username, password)
return ldap.bind(username, password);
end
function provider.user_exists(username)
local params = ldap.getparams()
local filter = ldap.filter.combine_and(params.user.filter, params.user.usernamefield .. '=' .. username);
if params.user.usernamefield == 'mail' then
filter = ldap.filter.combine_and(params.user.filter, 'mail=' .. username .. '@*');
end
return ldap.singlematch {
base = params.user.basedn,
filter = filter,
};
end
function provider.get_password(username)
return nil, "Passwords unavailable for LDAP.";
end
function provider.set_password(username, password)
return nil, "Passwords unavailable for LDAP.";
end
function provider.create_user(username, password)
return nil, "Account creation/modification not available with LDAP.";
end
function provider.get_sasl_handler(session)
local testpass_authentication_profile = {
session = session,
plain_test = function(sasl, username, password, realm)
return provider.test_password(username, password), true;
end,
order = { "plain_test" },
};
return new_sasl(module.host, testpass_authentication_profile);
end
function provider.is_admin(jid)
local admin_config = ldap.getparams().admin;
if not admin_config then
return;
end
local ld = ldap:getconnection();
local username = jsplit(jid);
local filter = ldap.filter.combine_and(admin_config.filter, admin_config.namefield .. '=' .. username);
return ldap.singlematch {
base = admin_config.basedn,
filter = filter,
};
end
return provider;
end
module:add_item("auth-provider", new_default_provider(module.host));

View file

@ -0,0 +1,86 @@
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local st = require "util.stanza";
local t_concat = table.concat;
local secure_auth_only = module:get_option("c2s_require_encryption")
or module:get_option("require_encryption")
or not(module:get_option("allow_unencrypted_plain_auth"));
local sessionmanager = require "core.sessionmanager";
local usermanager = require "core.usermanager";
local nodeprep = require "util.encodings".stringprep.nodeprep;
local resourceprep = require "util.encodings".stringprep.resourceprep;
module:add_feature("jabber:iq:auth");
module:hook("stream-features", function(event)
local origin, features = event.origin, event.features;
if secure_auth_only and not origin.secure then
-- Sorry, not offering to insecure streams!
return;
elseif not origin.username then
features:tag("auth", {xmlns='http://jabber.org/features/iq-auth'}):up();
end
end);
module:hook("stanza/iq/jabber:iq:auth:query", function(event)
local session, stanza = event.origin, event.stanza;
if session.type ~= "c2s_unauthed" then
(session.sends2s or session.send)(st.error_reply(stanza, "cancel", "service-unavailable", "Legacy authentication is only allowed for unauthenticated client connections."));
return true;
end
if secure_auth_only and not session.secure then
session.send(st.error_reply(stanza, "modify", "not-acceptable", "Encryption (SSL or TLS) is required to connect to this server"));
return true;
end
local username = stanza.tags[1]:child_with_name("username");
local password = stanza.tags[1]:child_with_name("password");
local resource = stanza.tags[1]:child_with_name("resource");
if not (username and password and resource) then
local reply = st.reply(stanza);
session.send(reply:query("jabber:iq:auth")
:tag("username"):up()
:tag("password"):up()
:tag("resource"):up());
else
username, password, resource = t_concat(username), t_concat(password), t_concat(resource);
username = nodeprep(username);
resource = resourceprep(resource)
if not (username and resource) then
session.send(st.error_reply(stanza, "modify", "bad-request"));
return true;
end
if usermanager.test_password(username, session.host, password) then
-- Authentication successful!
local success, err = sessionmanager.make_authenticated(session, username);
if success then
local err_type, err_msg;
success, err_type, err, err_msg = sessionmanager.bind_resource(session, resource);
if not success then
session.send(st.error_reply(stanza, err_type, err, err_msg));
session.username, session.type = nil, "c2s_unauthed"; -- FIXME should this be placed in sessionmanager?
return true;
elseif resource ~= session.resource then -- server changed resource, not supported by legacy auth
session.send(st.error_reply(stanza, "cancel", "conflict", "The requested resource could not be assigned to this session."));
session:close(); -- FIXME undo resource bind and auth instead of closing the session?
return true;
end
end
session.send(st.reply(stanza));
else
session.send(st.error_reply(stanza, "auth", "not-authorized"));
end
end
return true;
end);

View file

@ -0,0 +1,243 @@
-- vim:sts=4 sw=4
-- Metronome IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2012 Rob Hoelz
-- Copyright (C) 2015 YUNOHOST.ORG
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
----------------------------------------
-- Constants and such --
----------------------------------------
local setmetatable = setmetatable;
local get_config = require "core.configmanager".get;
local ldap = module:require 'ldap';
local vcardlib = module:require 'vcard';
local st = require 'util.stanza';
local gettime = require 'socket'.gettime;
local log = module._log
if not ldap then
return;
end
local CACHE_EXPIRY = 300;
----------------------------------------
-- Utility Functions --
----------------------------------------
local function ldap_record_to_vcard(record, format)
return vcardlib.create {
record = record,
format = format,
}
end
local get_alias_for_user;
do
local user_cache;
local last_fetch_time;
local function populate_user_cache()
local user_c = get_config(module.host, 'ldap').user;
if not user_c then return; end
local ld = ldap.getconnection();
local usernamefield = user_c.usernamefield;
local namefield = user_c.namefield;
user_cache = {};
for _, attrs in ld:search { base = user_c.basedn, scope = 'onelevel', filter = user_c.filter } do
user_cache[attrs[usernamefield]] = attrs[namefield];
end
last_fetch_time = gettime();
end
function get_alias_for_user(user)
if last_fetch_time and last_fetch_time + CACHE_EXPIRY < gettime() then
user_cache = nil;
end
if not user_cache then
populate_user_cache();
end
return user_cache[user];
end
end
----------------------------------------
-- Base LDAP store class --
----------------------------------------
local function ldap_store(config)
local self = {};
local config = config;
function self:get(username)
return nil, "Data getting is not available for this storage backend";
end
function self:set(username, data)
return nil, "Data setting is not available for this storage backend";
end
return self;
end
local adapters = {};
----------------------------------------
-- Roster Storage Implementation --
----------------------------------------
adapters.roster = function (config)
-- Validate configuration requirements
if not config.groups then return nil; end
local self = ldap_store(config)
function self:get(username)
local ld = ldap.getconnection();
local contacts = {};
local memberfield = config.groups.memberfield;
local namefield = config.groups.namefield;
local filter = memberfield .. '=' .. tostring(username);
local groups = {};
for _, config in ipairs(config.groups) do
groups[ config[namefield] ] = config.name;
end
log("debug", "Found %d group(s) for user %s", select('#', groups), username)
-- XXX this kind of relies on the way we do groups at INOC
for _, attrs in ld:search { base = config.groups.basedn, scope = 'onelevel', filter = filter } do
if groups[ attrs[namefield] ] then
local members = attrs[memberfield];
for _, user in ipairs(members) do
if user ~= username then
local jid = user .. '@' .. module.host;
local record = contacts[jid];
if not record then
record = {
subscription = 'both',
groups = {},
name = get_alias_for_user(user),
};
contacts[jid] = record;
end
record.groups[ groups[ attrs[namefield] ] ] = true;
end
end
end
end
return contacts;
end
function self:set(username, data)
log("warn", "Setting data in Roster LDAP storage is not supported yet")
return nil, "not supported";
end
return self;
end
----------------------------------------
-- vCard Storage Implementation --
----------------------------------------
adapters.vcard = function (config)
-- Validate configuration requirements
if not config.vcard_format or not config.user then return nil; end
local self = ldap_store(config)
function self:get(username)
local ld = ldap.getconnection();
local filter = config.user.usernamefield .. '=' .. tostring(username);
log("debug", "Retrieving vCard for user '%s'", username);
local match = ldap.singlematch {
base = config.user.basedn,
filter = filter,
};
if match then
match.jid = username .. '@' .. module.host
return st.preserialize(ldap_record_to_vcard(match, config.vcard_format));
else
return nil, "username not found";
end
end
function self:set(username, data)
log("warn", "Setting data in vCard LDAP storage is not supported yet")
return nil, "not supported";
end
return self;
end
----------------------------------------
-- Driver Definition --
----------------------------------------
cache = {};
local driver = { name = "ldap" };
function driver:open(store)
log("debug", "Opening ldap storage backend for host '%s' and store '%s'", module.host, store);
if not cache[module.host] then
log("debug", "Caching adapters for the host '%s'", module.host);
local ad_config = get_config(module.host, "ldap");
local ad_cache = {};
for k, v in pairs(adapters) do
ad_cache[k] = v(ad_config);
end
cache[module.host] = ad_cache;
end
local adapter = cache[module.host][store];
if not adapter then
log("info", "Unavailable adapter for store '%s'", store);
return nil, "unsupported-store";
end
return adapter;
end
function driver:stores(username, type, pattern)
return nil, "not implemented";
end
function driver:store_exists(username, type)
return nil, "not implemented";
end
function driver:purge(username)
return nil, "not implemented";
end
function driver:nodes(type)
return nil, "not implemented";
end
module:add_item("data-driver", driver);

View file

@ -0,0 +1,162 @@
-- vim:sts=4 sw=4
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2012 Rob Hoelz
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local st = require 'util.stanza';
local VCARD_NS = 'vcard-temp';
local builder_methods = {};
local base64_encode = require('util.encodings').base64.encode;
function builder_methods:addvalue(key, value)
self.vcard:tag(key):text(value):up();
end
function builder_methods:addphotofield(tagname, format_section)
local record = self.record;
local format = self.format;
local vcard = self.vcard;
local config = format[format_section];
if not config then
return;
end
if config.extval then
if record[config.extval] then
local tag = vcard:tag(tagname);
tag:tag('EXTVAL'):text(record[config.extval]):up();
end
elseif config.type and config.binval then
if record[config.binval] then
local tag = vcard:tag(tagname);
tag:tag('TYPE'):text(config.type):up();
tag:tag('BINVAL'):text(base64_encode(record[config.binval])):up();
end
else
module:log('error', 'You have an invalid %s config section', tagname);
return;
end
vcard:up();
end
function builder_methods:addregularfield(tagname, format_section)
local record = self.record;
local format = self.format;
local vcard = self.vcard;
if not format[format_section] then
return;
end
local tag = vcard:tag(tagname);
for k, v in pairs(format[format_section]) do
tag:tag(string.upper(k)):text(record[v]):up();
end
vcard:up();
end
function builder_methods:addmultisectionedfield(tagname, format_section)
local record = self.record;
local format = self.format;
local vcard = self.vcard;
if not format[format_section] then
return;
end
for k, v in pairs(format[format_section]) do
local tag = vcard:tag(tagname);
if type(k) == 'string' then
tag:tag(string.upper(k)):up();
end
for k2, v2 in pairs(v) do
if type(v2) == 'boolean' then
tag:tag(string.upper(k2)):up();
else
tag:tag(string.upper(k2)):text(record[v2]):up();
end
end
vcard:up();
end
end
function builder_methods:build()
local record = self.record;
local format = self.format;
self:addvalue( 'VERSION', '2.0');
self:addvalue( 'FN', record[format.displayname]);
self:addregularfield( 'N', 'name');
self:addvalue( 'NICKNAME', record[format.nickname]);
self:addphotofield( 'PHOTO', 'photo');
self:addvalue( 'BDAY', record[format.birthday]);
self:addmultisectionedfield('ADR', 'address');
self:addvalue( 'LABEL', nil); -- we don't support LABEL...yet.
self:addmultisectionedfield('TEL', 'telephone');
self:addmultisectionedfield('EMAIL', 'email');
self:addvalue( 'JABBERID', record.jid);
self:addvalue( 'MAILER', record[format.mailer]);
self:addvalue( 'TZ', record[format.timezone]);
self:addregularfield( 'GEO', 'geo');
self:addvalue( 'TITLE', record[format.title]);
self:addvalue( 'ROLE', record[format.role]);
self:addphotofield( 'LOGO', 'logo');
self:addvalue( 'AGENT', nil); -- we don't support AGENT...yet.
self:addregularfield( 'ORG', 'org');
self:addvalue( 'CATEGORIES', nil); -- we don't support CATEGORIES...yet.
self:addvalue( 'NOTE', record[format.note]);
self:addvalue( 'PRODID', nil); -- we don't support PRODID...yet.
self:addvalue( 'REV', record[format.rev]);
self:addvalue( 'SORT-STRING', record[format.sortstring]);
self:addregularfield( 'SOUND', 'sound');
self:addvalue( 'UID', record[format.uid]);
self:addvalue( 'URL', record[format.url]);
self:addvalue( 'CLASS', nil); -- we don't support CLASS...yet.
self:addregularfield( 'KEY', 'key');
self:addvalue( 'DESC', record[format.description]);
return self.vcard;
end
local function new_builder(params)
local vcard_tag = st.stanza('vCard', { xmlns = VCARD_NS });
local object = {
vcard = vcard_tag,
__index = builder_methods,
};
for k, v in pairs(params) do
object[k] = v;
end
setmetatable(object, object);
return object;
end
local _M = {};
function _M.create(params)
local builder = new_builder(params);
return builder:build();
end
return _M;

View file

@ -0,0 +1,8 @@
# Insert YunoHost button + portal overlay
sub_filter </head> '<script type="text/javascript" src="/ynh_portal.js"></script><link type="text/css" rel="stylesheet" href="/ynh_overlay.css"><script type="text/javascript" src="/ynhtheme/custom_portal.js"></script><link type="text/css" rel="stylesheet" href="/ynhtheme/custom_overlay.css"></head>';
sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json|ynhtheme/custom_portal.js|ynhtheme/custom_overlay.css) {
}

View file

@ -0,0 +1,7 @@
# Avoid the nginx path/alias traversal weakness ( #1037 )
rewrite ^/yunohost/sso$ /yunohost/sso/ permanent;
location /yunohost/sso/ {
# This is an empty location, only meant to avoid other locations
# from matching /yunohost/sso, such that it's correctly handled by ssowat
}

View file

@ -3,16 +3,16 @@ ssl_session_cache shared:SSL:50m; # about 200000 sessions
ssl_session_tickets off;
{% if compatibility == "modern" %}
# 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.22.1&config=modern&openssl=3.0.9&guideline=5.7
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, modern configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=modern&openssl=1.1.1d&guideline=5.6
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
{% else %}
# Ciphers with intermediate compatibility
# 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.22.1&config=intermediate&openssl=3.0.9&guideline=5.7
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6
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:DHE-RSA-CHACHA20-POLY1305;
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_prefer_server_ciphers off;
# Pre-defined FFDHE group (RFC 7919)

View file

@ -6,7 +6,7 @@ map $http_upgrade $connection_upgrade {
server {
listen 80;
listen [::]:80;
server_name {{ domain }};
server_name {{ domain }}{% if xmpp_enabled == "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %};
access_by_lua_file /usr/share/ssowat/access.lua;
@ -78,3 +78,48 @@ server {
access_log /var/log/nginx/{{ domain }}-access.log;
error_log /var/log/nginx/{{ domain }}-error.log;
}
{% if xmpp_enabled == "True" %}
# vhost dedicated to XMPP http_upload
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name xmpp-upload.{{ domain }};
root /dev/null;
location /upload/ {
alias /var/xmpp-upload/{{ domain }}/upload/;
# Pass all requests to metronome, except for GET and HEAD requests.
limit_except GET HEAD {
proxy_pass http://localhost:5290;
}
include proxy_params;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'HEAD, GET, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
client_max_body_size 105M; # Choose a value a bit higher than the max upload configured in XMPP server
}
include /etc/nginx/conf.d/security.conf.inc;
ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem;
{% if domain_cert_ca != "selfsigned" %}
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
{% endif %}
{% if domain_cert_ca == "letsencrypt" %}
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
resolver 1.1.1.1 9.9.9.9 valid=300s;
resolver_timeout 5s;
{% endif %}
access_log /var/log/nginx/xmpp-upload.{{ domain }}-access.log;
error_log /var/log/nginx/xmpp-upload.{{ domain }}-error.log;
}
{% endif %}

View file

@ -23,24 +23,3 @@ location = /yunohost/api/error/502 {
add_header Content-Type text/plain;
internal;
}
location /yunohost/portalapi/ {
proxy_read_timeout 5s;
proxy_pass http://127.0.0.1:6788/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# Custom 502 error page
error_page 502 /yunohost/portalapi/error/502;
}
# Yunohost admin output complete 502 error page, so use only plain text.
location = /yunohost/portalapi/error/502 {
return 502 '502 - Bad Gateway';
add_header Content-Type text/plain;
internal;
}

View file

@ -1,21 +0,0 @@
# Avoid the nginx path/alias traversal weakness ( #1037 )
rewrite ^/yunohost/sso$ /yunohost/sso/ permanent;
location /yunohost/sso/ {
alias /usr/share/yunohost/portal/;
default_type text/html;
index index.html;
try_files $uri $uri/ /index.html;
location = /yunohost/sso/index.html {
etag off;
expires off;
more_set_headers "Cache-Control: no-store, no-cache, must-revalidate";
}
location /yunohost/sso/applogos/ {
alias /usr/share/yunohost/applogos/;
}
more_set_headers "Content-Security-Policy: upgrade-insecure-requests; default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; object-src 'none'; img-src 'self' data:;";
}

View file

@ -1,31 +0,0 @@
# General daemon config
Socket inet:8891@localhost
PidFile /run/opendkim/opendkim.pid
UserID opendkim
UMask 007
AutoRestart yes
AutoRestartCount 10
AutoRestartRate 10/1h
# Logging
Syslog yes
SyslogSuccess yes
LogWhy yes
# Common signing and verification parameters. In Debian, the "From" header is
# oversigned, because it is often the identity key used by reputation systems
# and thus somewhat security sensitive.
Canonicalization relaxed/simple
Mode sv
OversignHeaders From
#On-BadSignature reject
# Key / signing table
KeyTable file:/etc/dkim/keytable
SigningTable refile:/etc/dkim/signingtable
# The trust anchor enables DNSSEC. In Debian, the trust anchor file is provided
# by the package dns-root-data.
TrustAnchorFile /usr/share/dns/root.key
#Nameservers 127.0.0.1

View file

@ -30,8 +30,8 @@ smtpd_tls_chain_files =
tls_server_sni_maps = hash:/etc/postfix/sni
{% if compatibility == "intermediate" %}
# 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.7.5&config=intermediate&openssl=3.0.9&guideline=5.7
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, intermediate configuration
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=intermediate&openssl=1.1.1d&guideline=5.6
smtpd_tls_mandatory_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
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:DHE-RSA-CHACHA20-POLY1305
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
{% else %}
# 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.7.5&config=modern&openssl=3.0.9&guideline=5.7
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, modern configuration
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=modern&openssl=1.1.1d&guideline=5.6
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
@ -182,10 +182,9 @@ smtp_header_checks = regexp:/etc/postfix/header_checks
smtp_reply_filter = pcre:/etc/postfix/smtp_reply_filter
# Rmilter
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} {auth_type}
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
smtpd_milters = inet:localhost:11332
# Skip email without checking if milter has died
milter_default_action = accept
@ -212,3 +211,11 @@ smtp_sasl_security_options = noanonymous
# where to find sasl_passwd
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
{% endif %}
{% if backup_mx_domains != "" %}
# Backup MX (secondary MX)
relay_domains = $mydestination {{backup_mx_domains}}
relay_recipient_maps = hash:/etc/postfix/relay_recipients
maximal_queue_lifetime = 20d
{% endif %}

View file

@ -0,0 +1,16 @@
allow_envfrom_empty = true;
allow_hdrfrom_mismatch = false;
allow_hdrfrom_multiple = false;
allow_username_mismatch = true;
auth_only = true;
path = "/etc/dkim/$domain.$selector.key";
selector = "mail";
sign_local = true;
symbol = "DKIM_SIGNED";
try_fallback = true;
use_domain = "header";
use_esld = false;
use_redis = false;
key_prefix = "DKIM_KEYS";

View file

@ -0,0 +1,8 @@
# Metrics settings
# This define overridden options.
actions {
reject = 21;
add_header = 8;
greylist = 4;
}

View file

@ -0,0 +1,9 @@
use = ["spam-header"];
routines {
spam-header {
header = "X-Spam";
value = "Yes";
remove = 1;
}
}

2
conf/rspamd/redis.conf Normal file
View file

@ -0,0 +1,2 @@
# set redis server
servers = "127.0.0.1";

4
conf/rspamd/rspamd.sieve Normal file
View file

@ -0,0 +1,4 @@
require ["fileinto"];
if header :is "X-Spam" "Yes" {
fileinto "Junk";
}

View file

@ -56,6 +56,7 @@ objectClass: groupOfNamesYnh
gidNumber: 4002
cn: all_users
permission: cn=mail.main,ou=permission,dc=yunohost,dc=org
permission: cn=xmpp.main,ou=permission,dc=yunohost,dc=org
dn: cn=visitors,ou=groups,dc=yunohost,dc=org
objectClass: posixGroup
@ -74,6 +75,17 @@ gidNumber: 5001
showTile: FALSE
authHeader: FALSE
dn: cn=xmpp.main,ou=permission,dc=yunohost,dc=org
groupPermission: cn=all_users,ou=groups,dc=yunohost,dc=org
cn: xmpp.main
objectClass: posixGroup
objectClass: permissionYnh
isProtected: TRUE
label: XMPP
gidNumber: 5002
showTile: FALSE
authHeader: FALSE
dn: cn=ssh.main,ou=permission,dc=yunohost,dc=org
cn: ssh.main
objectClass: posixGroup

View file

@ -84,7 +84,7 @@ Subsystem sftp internal-sftp
# Apply following instructions to user with sftp perm only
Match Group sftp.main,!ssh.main
ForceCommand internal-sftp
ForceCommand internal-sftp -u 0002
# We can't restrict to /home/%u because the chroot base must be owned by root
# So we chroot only on /home
# See https://serverfault.com/questions/584986/bad-ownership-or-modes-for-chroot-directory-component
@ -97,7 +97,7 @@ Match Group sftp.main,!ssh.main
PermitUserRC no
Match Group sftp.app,!ssh.app
ForceCommand internal-sftp
ForceCommand internal-sftp -u 0002
ChrootDirectory %h
AllowTcpForwarding no
AllowStreamLocalForwarding no

View file

@ -192,7 +192,7 @@ authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName=DNS:yunohost.org,DNS:www.yunohost.org,DNS:ns.yunohost.org
subjectAltName=DNS:yunohost.org,DNS:www.yunohost.org,DNS:ns.yunohost.org,DNS:xmpp-upload.yunohost.org
[ v3_ca ]

View file

@ -8,6 +8,11 @@ fail2ban:
log: /var/log/fail2ban.log
category: security
test_conf: fail2ban-server --test
metronome:
log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err]
needs_exposed_ports: [5222, 5269]
category: xmpp
ignore_if_package_is_not_installed: metronome
mysql:
log: [/var/log/mysql.log,/var/log/mysql.err,/var/log/mysql/error.log]
actual_systemd_service: mariadb
@ -23,22 +28,21 @@ nginx:
# log: /var/log/php7.4-fpm.log
# test_conf: php-fpm7.4 --test
# category: web
opendkim:
category: email
test_conf: opendkim -n
postfix:
log: [/var/log/mail.log,/var/log/mail.err]
actual_systemd_service: postfix@-
needs_exposed_ports: [25, 587]
category: email
postgresql:
actual_systemd_service: 'postgresql@15-main'
actual_systemd_service: 'postgresql@13-main'
category: database
ignore_if_package_is_not_installed: postgresql-15
ignore_if_package_is_not_installed: postgresql-13
redis-server:
log: /var/log/redis/redis-server.log
category: database
ignore_if_package_is_not_installed: redis-server
rspamd:
log: /var/log/rspamd/rspamd.log
category: email
slapd:
category: database
test_conf: slapd -Tt
@ -47,9 +51,6 @@ ssh:
test_conf: sshd -t
needs_exposed_ports: [22]
category: admin
yunohost-portal-api:
log: /var/log/yunohost-portal-api.log
category: userportal
yunohost-api:
log: /var/log/yunohost/yunohost-api.log
category: admin
@ -59,6 +60,21 @@ yunohost-firewall:
category: security
yunomdns:
category: mdns
glances: null
nsswitch: null
ssl: null
yunohost: null
bind9: null
tahoe-lafs: null
memcached: null
udisks2: null
udisk-glue: null
amavis: null
postgrey: null
spamassassin: null
rmilter: null
php5-fpm: null
php7.0-fpm: null
php7.3-fpm: null
nslcd: null
avahi-daemon: null

View file

@ -1,48 +0,0 @@
[Unit]
Description=YunoHost Portal API
After=network.target
[Service]
User=ynh-portal
Group=ynh-portal
Type=simple
ExecStart=/usr/bin/yunohost-portal-api
Restart=always
RestartSec=5
TimeoutStopSec=30
# Sandboxing options to harden security
# Details for these options: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
DevicePolicy=closed
ProtectClock=yes
ProtectHostname=yes
ProtectProc=invisible
ProtectSystem=full
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
LockPersonality=yes
SystemCallArchitectures=native
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap @cpu-emulation @privileged
# Denying access to capabilities that should not be relevant
# Doc: https://man7.org/linux/man-pages/man7/capabilities.7.html
CapabilityBoundingSet=~CAP_RAWIO CAP_MKNOD
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_TIME CAP_SYS_MODULE CAP_SYS_PACCT
CapabilityBoundingSet=~CAP_LEASE CAP_LINUX_IMMUTABLE CAP_IPC_LOCK
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_WAKE_ALARM
CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE
CapabilityBoundingSet=~CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW
CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYSLOG
[Install]
WantedBy=multi-user.target

69
debian/changelog vendored
View file

@ -1,41 +1,52 @@
yunohost (12.0.2) testing; urgency=low
yunohost (11.2.30) stable; urgency=low
- Cleanup redis regen conf since redis ain't installed by default anymore (7b50c4eb6)
- bullseye->bookworm: add a trick to flag the migration as done if it's still marked as pending (0503a38a7)
- Sync with main branch
- helpers v2.1: check if patches dir exists before getting realpath ([#1938](http://github.com/YunoHost/yunohost/pull/1938))
- helpers v2.1: ynh_add_swap and ynh_smart_mktemp (aff885e6b)
- helpers v2.1: fix ynh_restore_everything ([#1943](http://github.com/YunoHost/yunohost/pull/1943))
- helpers v2.1: fix typo in docs: ynh_install_app_dependencies -> ynh_apt_install_dependencies ([#1939](http://github.com/YunoHost/yunohost/pull/1939))
- helpers: fix syntax, disambiguate subshell syntax ([#1940](http://github.com/YunoHost/yunohost/pull/1940))
- quality: Add maintenante/shfmt.sh for shell script formatting (68f35831e)
- quality: Apply shfmt everywhere, fix tabs/space/indent (8a5f2808a, e3ddb1dc4, ef1708276, 38b39ebae, b91e9dd8f)
Thanks to all contributors <3 ! (Kayou)
Thanks to all contributors <3 ! (Félix Piédallu, Josué Tille, OniriCorpe, selfhoster1312)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 01 Aug 2024 18:08:33 +0200
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 31 Aug 2024 19:26:59 +0200
yunohost (12.0.1) testing; urgency=low
yunohost (11.2.29) stable; urgency=low
- The user portal and SSO system have been reworked and split into three distinct pieces
- SSOwat only handling only the SSO/ACL logic (nginx lua middleware)
- A new “portal API” (yunohost-portal-api) service delivering authentication cookies and allowing users to retrieve/update infos
- A new portal front end (yunohost-portal)
- More information on the release note on the forum
- The base system does not install Mysql/Mariadb and PHP anymore
- Rspamd (antispam system) and Metronome (XMPP server) are not part of the core anymore. Instead, they are now separate applications : rspamd_ynh and metronome_ynh
- webadmin: rework cookie/session expiration mechanism. Cookies are now still valid after restarting the API (preventing clumsy disconnect during self-upgrades) and the cookie validity is automatically extended every time an API request is performed.
- mail: DKIM email signing is now done using opendkim instead of rspamd
- various compatibility tweakings for Bookworm
- regenconf: update nginx and dovecot ciphers according to Mozilla recommendation
- regenconf: update fail2ban config
- configpanels: refactor to use pydantic for more typing and consistency, add proper autogenerated doc
- apps: Yarn third-party repo is now available by default in apt config just like Sury, no need for an extra apt resource thingy
- various legacy cleanups (more info on the release note on the forum)
- perf: minimize regen-conf calls to yunohost settings get, and other misc lazy-loading optimizations
- quality: simplify the logging mess
- quality: rework ci tests workflow
- apps: generalize replacing __INSTALL_DIR__ and __APP__ in config panel 'bind' statement to any setting (9b0553580)
- apps/config panels: move the computation of the actual 'bind' value to the python core (a6785d34b)
- perf: add cache for _get_app_settings() (c14ebc8be, 7c7906046)
- quality: use _assert_is_installed for consistency instead of if not _is_intalled(app): raise (c409888a4)
- i18n: Translations updated for Basque, French, Galician, Greek, Indonesian
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 26 Jul 2024 22:40:16 +0200
Thanks to all contributors <3 ! (cjdw, craftrac, José M, ppr, xabirequejo)
yunohost (12.0.0) unstable; urgency=low
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 27 Aug 2024 14:46:26 +0200
- Tmp changelog to prepare Bookworm
yunohost (11.2.28) stable; urgency=low
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 04 May 2023 20:30:19 +0200
- ci: various changes due to CI infrastructure changes (200f0272d, 764fe6a7b, 9083a5cc3, d0df3caed, 6733526be, df320a44c, 92f4a605b, f02d4a437, c5953b542)
- apps: exclude .well-known subpaths from conflict checks ([#1647](http://github.com/YunoHost/yunohost/pull/1647))
- apps: in apt resource, fix empty string in packages_from_raw_bash breaking dpkg-build (a76cd05e8)
- sftp: Tweak umask for SFTP ([#1384](http://github.com/YunoHost/yunohost/pull/1384))
- mail: Be able to use postfix as a backup ("secondary") MX hosts ([#1253](http://github.com/YunoHost/yunohost/pull/1253))
- diagnosis: Add check regarding rfkill blocking Wi-Fi card on RPi ([#1841](http://github.com/YunoHost/yunohost/pull/1841))
- users: trigger hooks when adding or removing user into group (51787a2f8)
- i18n: Translations updated for Basque, French, Indonesian, Russian
Thanks to all contributors <3 ! (cjdw, Emmanuel Averty, Ivan Davydov, ljf, ppr, Tagada, tituspijean, xabirequejo)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 25 Aug 2024 13:17:43 +0200
yunohost (11.2.27) stable; urgency=low
- apt resource: fix handling of empty 'packages' list breaking dpkg-deb call (3deffdbd5)
- i18n: Translations updated for Indonesian, Turkish
Thanks to all contributors <3 ! (Ali Çıır, cjdw)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 03 Aug 2024 18:41:27 +0200
yunohost (11.2.26) stable; urgency=low

40
debian/control vendored
View file

@ -2,22 +2,21 @@ Source: yunohost
Section: utils
Priority: extra
Maintainer: YunoHost Contributors <contrib@yunohost.org>
Build-Depends: debhelper (>=9), debhelper-compat (= 13), dh-python, python3-all (>= 3.11), python3-yaml, python3-jinja2 (>= 3.0)
Build-Depends: debhelper (>=9), debhelper-compat (= 13), dh-python, python3-all (>= 3.7), python3-yaml, python3-jinja2
Standards-Version: 3.9.6
Homepage: https://yunohost.org/
Package: yunohost
Essential: yes
Architecture: all
Depends: python3-all (>= 3.11),
, moulinette (>= 12.0), ssowat (>= 12.0),
Depends: ${python3:Depends}, ${misc:Depends}
, moulinette (>= 11.1), moulinette (<< 12.0), ssowat (>= 11.1), ssowat (<< 12.0)
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
, python3-miniupnpc, python3-dbus, python3-jinja2 (>= 3.0)
, python3-miniupnpc, python3-dbus, python3-jinja2
, python3-toml, python3-packaging, python3-publicsuffix2
, python3-ldap, python3-zeroconf (>= 0.47), python3-lexicon,
, python3-cryptography, python3-jwt, python3-passlib, python3-magic
, python-is-python3, python3-pydantic, python3-email-validator
, nginx, nginx-extras (>=1.22)
, python3-ldap, python3-zeroconf (>= 0.36), python3-lexicon,
, python-is-python3
, nginx, nginx-extras (>=1.18)
, apt, apt-transport-https, apt-utils, aptitude, dirmngr
, openssh-server, iptables, fail2ban, bind9-dnsutils
, openssl, ca-certificates, netcat-openbsd, iproute2
@ -25,26 +24,31 @@ Depends: python3-all (>= 3.11),
, dnsmasq, resolvconf, libnss-myhostname
, postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre
, dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam
, opendkim-tools, opendkim, postsrsd, procmail, mailutils
, rspamd, opendkim-tools, postsrsd, procmail, mailutils
, redis-server
, acl
, git, curl, wget, cron, unzip, jq, bc, at, procps, j2cli
, lsb-release, haveged, fake-hwclock, lsof, whois
Recommends: yunohost-admin, yunohost-portal (>= 12.0)
Recommends: yunohost-admin
, ntp, inetutils-ping | iputils-ping
, 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
, libdbd-ldap-perl, libnet-dns-perl
, metronome (>=3.14.0)
Conflicts: iptables-persistent
, apache2
, bind9
, openresolv
, systemd-resolved
, nginx-extras (>= 1.23)
, openssl (>= 3.1)
, slapd (>= 2.6)
, dovecot-core (>= 1:2.4)
, fail2ban (>= 1.1)
, iptables (>= 1.8.10)
, nginx-extras (>= 1.19)
, openssl (>= 3.0)
, slapd (>= 2.4.58)
, dovecot-core (>= 1:2.3.14)
, redis-server (>= 5:6.1)
, fail2ban (>= 0.11.3)
, iptables (>= 1.8.8)
Description: manageable and configured self-hosting server
YunoHost aims to make self-hosting accessible to everyone. It configures
an email, Web and IM server alongside a LDAP base. It also provides

1
debian/install vendored
View file

@ -6,4 +6,5 @@ conf/* /usr/share/yunohost/conf/
locales/* /usr/share/yunohost/locales/
doc/yunohost.8.gz /usr/share/man/man8/
doc/bash_completion.d/* /etc/bash_completion.d/
conf/metronome/modules/* /usr/lib/metronome/modules/
src/* /usr/lib/python3/dist-packages/yunohost/

8
debian/postinst vendored
View file

@ -4,10 +4,6 @@ set -e
do_configure() {
mkdir -p /etc/yunohost
mkdir -p /etc/yunohost/apps
mkdir -p /etc/yunohost/portal
if [ ! -f /etc/yunohost/installed ]; then
# If apps/ is not empty, we're probably already installed in the past and
# something funky happened ...
@ -31,14 +27,12 @@ do_configure() {
yunohost tools migrations run --auto
echo "Re-diagnosing server health..."
yunohost diagnosis run --force
[[ -n "${YNH_SKIP_DIAGNOSIS_DURING_UPGRADE:-}" ]] && echo "(Skipping)" || yunohost diagnosis run --force
echo "Refreshing app catalog..."
yunohost tools update apps --output-as none || true
fi
systemctl restart yunohost-portal-api
# Trick to let yunohost handle the restart of the API,
# to prevent the webadmin from cutting the branch it's sitting on
if systemctl is-enabled yunohost-api --quiet

View file

@ -1,181 +0,0 @@
import ast
import datetime
import subprocess
version = open("../debian/changelog").readlines()[0].split()[1].strip("()")
today = datetime.datetime.now().strftime("%d/%m/%Y")
def get_current_commit():
p = subprocess.Popen(
"git rev-parse --verify HEAD",
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
stdout, stderr = p.communicate()
current_commit = stdout.strip().decode("utf-8")
return current_commit
current_commit = get_current_commit()
def print_config_panel_docs():
fname = "../src/utils/configpanel.py"
content = open(fname).read()
# NB: This magic is because we want to be able to run this script outside of a YunoHost context,
# in which we cant really 'import' the file because it will trigger a bunch of moulinette/yunohost imports...
tree = ast.parse(content)
ConfigPanelClasses = reversed(
[
c
for c in tree.body
if isinstance(c, ast.ClassDef)
and c.name in {"SectionModel", "PanelModel", "ConfigPanelModel"}
]
)
print("## Configuration panel structure")
for c in ConfigPanelClasses:
doc = ast.get_docstring(c)
print("")
print(f"### {c.name.replace('Model', '')}")
print("")
print(doc)
print("")
print("---")
def print_form_doc():
fname = "../src/utils/form.py"
content = open(fname).read()
# NB: This magic is because we want to be able to run this script outside of a YunoHost context,
# in which we cant really 'import' the file because it will trigger a bunch of moulinette/yunohost imports...
tree = ast.parse(content)
OptionClasses = [
c
for c in tree.body
if isinstance(c, ast.ClassDef) and c.name.endswith("Option")
]
OptionDocString = {}
print("## List of all option types")
for c in OptionClasses:
if not isinstance(c.body[0], ast.Expr):
continue
option_type = None
if c.name in {"BaseOption", "BaseInputOption"}:
option_type = c.name
elif c.body[1].target.id == "type":
option_type = c.body[1].value.attr
generaltype = (
c.bases[0].id.replace("Option", "").replace("Base", "").lower()
if c.bases
else None
)
docstring = ast.get_docstring(c)
if docstring:
if "#### Properties" not in docstring:
docstring += """
#### Properties
- [common properties](#common-properties)"""
OptionDocString[option_type] = {
"doc": docstring,
"generaltype": generaltype,
}
# Dirty hack to have "BaseOption" as first and "BaseInputOption" as 2nd in list
base = OptionDocString.pop("BaseOption")
baseinput = OptionDocString.pop("BaseInputOption")
OptionDocString2 = {
"BaseOption": base,
"BaseInputOption": baseinput,
}
OptionDocString2.update(OptionDocString)
for option_type, infos in OptionDocString2.items():
if option_type == "display_text":
# display_text is kind of legacy x_x
continue
print("")
if option_type == "BaseOption":
print("### Common properties")
elif option_type == "BaseInputOption":
print("### Common inputs properties")
else:
print(
f"### `{option_type}`"
+ (f" ({infos['generaltype']})" if infos["generaltype"] else "")
)
print("")
print(infos["doc"])
print("")
print("---")
print(
rf"""---
title: Technical details for config panel structure and form option types
template: docs
taxonomy:
category: docs
routes:
default: '/dev/forms'
---
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{current_commit}/doc/generate_options_doc.py) on {today} (YunoHost version {version})
## Glossary
You may encounter some named types which are used for simplicity.
- `Translation`: a translated property
- used for properties: `ask`, `help` and `Pattern.error`
- a `dict` with locales as keys and translations as values:
```toml
ask.en = "The text in english"
ask.fr = "Le texte en français"
```
It is not currently possible for translators to translate those string in weblate.
- a single `str` for a single english default string
```toml
help = "The text in english"
```
- `JSExpression`: a `str` JS expression to be evaluated to `true` or `false`:
- used for properties: `visible` and `enabled`
- operators availables: `==`, `!=`, `>`, `>=`, `<`, `<=`, `!`, `&&`, `||`, `+`, `-`, `*`, `/`, `%` and `match()`
- `Binding`: bind a value to a file/property/variable/getter/setter/validator
- save the value in `settings.yaml` when not defined
- nothing at all with `"null"`
- a custom getter/setter/validator with `"null"` + a function starting with `get__`, `set__`, `validate__` in `scripts/config`
- a variable/property in a file with `:__FINALPATH__/my_file.php`
- a whole file with `__FINALPATH__/my_file.php`
- `Pattern`: a `dict` with a regex to match the value against and an error message
```toml
pattern.regexp = '^[A-F]\d\d$'
pattern.error = "Provide a room number such as F12: one uppercase and 2 numbers"
# or with translated error
pattern.error.en = "Provide a room number such as F12: one uppercase and 2 numbers"
pattern.error.fr = "Entrez un numéro de salle comme F12: une lettre majuscule et deux chiffres."
```
- IMPORTANT: your `pattern.regexp` should be between simple quote, not double.
"""
)
print_config_panel_docs()
print_form_doc()

View file

@ -1,4 +0,0 @@
from yunohost.utils.configpanel import ConfigPanelModel
print(ConfigPanelModel.schema_json(indent=2))

View file

@ -21,6 +21,7 @@ case "$YNH_HELPERS_VERSION" in
*)
echo "Helpers are not available in version '$YNH_HELPERS_VERSION'." >&2
exit 1
;;
esac
eval "$XTRACE_ENABLE"

View file

@ -19,8 +19,7 @@ ynh_install_apps() {
local apps_dependencies=""
# For each app
for one_app_and_its_args in "${apps_list[@]}"
do
for one_app_and_its_args in "${apps_list[@]}"; do
# Retrieve the name of the app (part before ?)
local one_app=$(cut -d "?" -f1 <<< "$one_app_and_its_args")
[ -z "$one_app" ] && ynh_die --message="You didn't provided a YunoHost app to install"
@ -28,8 +27,7 @@ ynh_install_apps() {
yunohost tools update apps
# Installing or upgrading the app depending if it's installed or not
if ! yunohost app list --output-as json --quiet | jq -e --arg id $one_app '.apps[] | select(.id == $id)' >/dev/null
then
if ! yunohost app list --output-as json --quiet | jq -e --arg id $one_app '.apps[] | select(.id == $id)' > /dev/null; then
# Retrieve the arguments of the app (part after ?)
local one_argument=""
if [[ "$one_app_and_its_args" == *"?"* ]]; then
@ -44,8 +42,7 @@ ynh_install_apps() {
yunohost app upgrade $one_app
fi
if [ ! -z "$apps_dependencies" ]
then
if [ ! -z "$apps_dependencies" ]; then
apps_dependencies="$apps_dependencies, $one_app"
else
apps_dependencies="$one_app"
@ -67,31 +64,26 @@ ynh_remove_apps() {
local apps_dependencies=$(ynh_app_setting_get --app=$app --key=apps_dependencies)
ynh_app_setting_delete --app=$app --key=apps_dependencies
if [ ! -z "$apps_dependencies" ]
then
if [ ! -z "$apps_dependencies" ]; then
# Split the list of apps dependencies in an array
local apps_dependencies_list=($(echo $apps_dependencies | tr ", " "\n"))
# For each apps dependencies
for one_app in "${apps_dependencies_list[@]}"
do
for one_app in "${apps_dependencies_list[@]}"; do
# Retrieve the list of installed apps
local installed_apps_list=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_by=""
local installed_app_required_by=""
# For each other installed app
for one_installed_app in $installed_apps_list
do
for one_installed_app in $installed_apps_list; do
# Retrieve the other apps dependencies
one_installed_apps_dependencies=$(ynh_app_setting_get --app=$one_installed_app --key=apps_dependencies)
if [ ! -z "$one_installed_apps_dependencies" ]
then
if [ ! -z "$one_installed_apps_dependencies" ]; then
one_installed_apps_dependencies_list=($(echo $one_installed_apps_dependencies | tr ", " "\n"))
# For each dependency of the other apps
for one_installed_app_dependency in "${one_installed_apps_dependencies_list[@]}"
do
for one_installed_app_dependency in "${one_installed_apps_dependencies_list[@]}"; do
if [[ $one_installed_app_dependency == $one_app ]]; then
required_by="$required_by $one_installed_app"
fi
@ -100,8 +92,7 @@ ynh_remove_apps() {
done
# If $one_app is no more required
if [[ -z "$required_by" ]]
then
if [[ -z "$required_by" ]]; then
# Remove $one_app
ynh_print_info --message="Removing of $one_app"
yunohost app remove $one_app --purge
@ -134,16 +125,14 @@ ynh_spawn_app_shell() {
ynh_handle_getopts_args "$@"
# Force Bash to be used to run this helper
if [[ ! $0 =~ \/?bash$ ]]
then
if [[ ! $0 =~ \/?bash$ ]]; then
ynh_print_err --message="Please use Bash as shell"
exit 1
fi
# Make sure the app is installed
local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id))
if [[ " ${installed_apps_list[*]} " != *" ${app} "* ]]
then
if [[ " ${installed_apps_list[*]} " != *" ${app} "* ]]; then
ynh_print_err --message="$app is not in the apps list"
exit 1
fi
@ -156,49 +145,44 @@ ynh_spawn_app_shell() {
# Make sure the app has an install_dir setting
local install_dir=$(ynh_app_setting_get --app=$app --key=install_dir)
if [ -z "$install_dir" ]
then
if [ -z "$install_dir" ]; then
ynh_print_err --message="$app has no install_dir setting (does it use packaging format >=2?)"
exit 1
fi
# Load the app's service name, or default to $app
local service=$(ynh_app_setting_get --app=$app --key=service)
[ -z "$service" ] && service=$app;
[ -z "$service" ] && service=$app
# Export HOME variable
export HOME=$install_dir;
export HOME=$install_dir
# Load the Environment variables from the app's service
local env_var=$(systemctl show $service.service -p "Environment" --value)
[ -n "$env_var" ] && export $env_var;
[ -n "$env_var" ] && export $env_var
# Force `php` to its intended version
# 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 phpflags=$(ynh_app_setting_get --app=$app --key=phpflags)
if [ -n "$phpversion" ]
then
if [ -n "$phpversion" ]; then
eval "php() { php${phpversion} ${phpflags} \"\$@\"; }"
export -f php
fi
# Source the EnvironmentFiles from the app's service
local env_files=($(systemctl show $service.service -p "EnvironmentFiles" --value))
if [ ${#env_files[*]} -gt 0 ]
then
if [ ${#env_files[*]} -gt 0 ]; then
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
set -a
for file in ${env_files[*]}
do
for file in ${env_files[*]}; do
[[ $file = /* ]] && source $file
done
set +a
fi
# Activate the Python environment, if it exists
if [ -f $install_dir/venv/bin/activate ]
then
if [ -f $install_dir/venv/bin/activate ]; then
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
set -a
source $install_dir/venv/bin/activate
@ -207,7 +191,7 @@ ynh_spawn_app_shell() {
# cd into the WorkingDirectory set in the service, or default to the install_dir
local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value)
[ -z $env_dir ] && env_dir=$install_dir;
[ -z $env_dir ] && env_dir=$install_dir
cd $env_dir
# Spawn the app shell

View file

@ -266,8 +266,7 @@ ynh_install_app_dependencies() {
# The (?<=php) syntax corresponds to lookbehind ;)
local specific_php_version=$(echo $dependencies | grep -oP '(?<=php)[0-9.]+(?=-|\>|)' | sort -u)
if [[ -n "$specific_php_version" ]]
then
if [[ -n "$specific_php_version" ]]; then
# Cover a small edge case where a packager could have specified "php7.4-pwet php5-gni" which is confusing
[[ $(echo $specific_php_version | wc -l) -eq 1 ]] \
|| ynh_die --message="Inconsistent php versions in dependencies ... found : $specific_php_version"
@ -281,8 +280,7 @@ ynh_install_app_dependencies() {
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
if [[ -f "$old_php_finalphpconf" ]]
then
if [[ -f "$old_php_finalphpconf" ]]; then
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
ynh_remove_fpm_config
fi
@ -291,8 +289,7 @@ ynh_install_app_dependencies() {
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
# Set the default php version back as the default version for php-cli.
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
then
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION; then
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
fi
elif grep --quiet 'php' <<< "$dependencies"; then
@ -306,13 +303,11 @@ ynh_install_app_dependencies() {
# upgrade script where ynh_install_app_dependencies is called with this
# expected effect) Otherwise, any subsequent call will add dependencies
# to those already present in the equivs control file.
if [[ $YNH_INSTALL_APP_DEPENDENCIES_REPLACE == "true" ]]
then
if [[ $YNH_INSTALL_APP_DEPENDENCIES_REPLACE == "true" ]]; then
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="false"
else
local current_dependencies=""
if ynh_package_is_installed --package="${dep_app}-ynh-deps"
then
if ynh_package_is_installed --package="${dep_app}-ynh-deps"; then
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
current_dependencies=${current_dependencies// | /|}
fi
@ -337,8 +332,7 @@ EOF
# Trigger postgresql regenconf if we may have just installed postgresql
local psql_installed2="$(ynh_package_is_installed "postgresql-$PSQL_VERSION" && echo yes || echo no)"
if [[ "$psql_installed" != "$psql_installed2" ]]
then
if [[ "$psql_installed" != "$psql_installed2" ]]; then
yunohost tools regen-conf postgresql
fi
@ -382,16 +376,14 @@ ynh_remove_app_dependencies() {
# Edge case where the app dep may be on hold,
# cf https://forum.yunohost.org/t/migration-error-cause-of-ffsync/20675/4
if apt-mark showhold | grep -q -w ${dep_app}-ynh-deps
then
if apt-mark showhold | grep -q -w ${dep_app}-ynh-deps; then
apt-mark unhold ${dep_app}-ynh-deps
fi
# Remove the fake package and its dependencies if they not still used.
# (except if dpkg doesn't know anything about the package,
# which should be symptomatic of a failed install, and we don't want bash to report an error)
if dpkg-query --show ${dep_app}-ynh-deps &>/dev/null
then
if dpkg-query --show ${dep_app}-ynh-deps &> /dev/null; then
ynh_package_autopurge ${dep_app}-ynh-deps
fi
}
@ -487,8 +479,10 @@ ynh_install_extra_repo() {
if [[ "${repo_parts[0]}" == "deb" ]]; then
index=1
fi
uri="${repo_parts[$index]}" ; index=$((index+1))
suite="${repo_parts[$index]}" ; index=$((index+1))
uri="${repo_parts[$index]}"
index=$((index + 1))
suite="${repo_parts[$index]}"
index=$((index + 1))
# Get the components
if (("${#repo_parts[@]}" > 0)); then

View file

@ -289,8 +289,7 @@ ynh_restore_file() {
# Boring hack for nginx conf file mapped to php7.3
# Note that there's no need to patch the fpm config because most php apps
# will call "ynh_add_fpm_config" during restore, effectively recreating the file from scratch
if [[ "${dest_path}" == "/etc/nginx/conf.d/"* ]] && grep 'php7.3.*sock' "${dest_path}"
then
if [[ "${dest_path}" == "/etc/nginx/conf.d/"* ]] && grep 'php7.3.*sock' "${dest_path}"; then
sed -i 's/php7.3/php7.4/g' "${dest_path}"
fi
}
@ -376,8 +375,7 @@ ynh_backup_if_checksum_is_different() {
echo "$backup_file_checksum" # Return the name of the backup file
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
local file_path_base64=$(echo "$file" | base64 -w0)
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}
then
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}; then
ynh_print_warn "Diff with the original file:"
diff --report-identical-files --unified --color=always /var/cache/yunohost/appconfbackup/original_${file_path_base64} $file >&2 || true
fi
@ -494,8 +492,7 @@ ynh_restore_upgradebackup() {
yunohost app remove $app
# Restore the backup
yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
if [[ -d /etc/yunohost/apps/$app ]]
then
if [[ -d /etc/yunohost/apps/$app ]]; then
ynh_die --message="The app was restored to the way it was before the failed upgrade."
else
ynh_die --message="Uhoh ... Yunohost failed to restore the app to the way it was before the failed upgrade :|"

View file

@ -22,7 +22,7 @@ _ynh_app_config_get_one() {
if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
old[$short_setting]="$(ls "$(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)" 2>/dev/null || echo YNH_NULL)"
old[$short_setting]="$(ls "$bind" 2> /dev/null || echo YNH_NULL)"
file_hash[$short_setting]="true"
# Get multiline text from settings or from a full file
@ -32,7 +32,7 @@ _ynh_app_config_get_one() {
elif [[ "$bind" == *":"* ]]; then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else
old[$short_setting]="$(cat $(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
old[$short_setting]="$(cat "$bind" 2> /dev/null || echo YNH_NULL)"
fi
# Get value from a kind of key/value file
@ -47,7 +47,7 @@ _ynh_app_config_get_one() {
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
local bind_file="$(echo "$bind" | cut -d: -f2)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
fi
@ -73,7 +73,7 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
local bind_file="$bind"
if [[ "${!short_setting}" == "" ]]; then
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_secure_remove --file="$bind_file"
@ -98,7 +98,7 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == *":"* ]]; then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
fi
local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
local bind_file="$bind"
ynh_backup_if_checksum_is_different --file="$bind_file"
echo "${!short_setting}" > "$bind_file"
ynh_store_file_checksum --file="$bind_file" --update_only
@ -113,7 +113,7 @@ _ynh_app_config_apply_one() {
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
bind_key_=${bind_key_:-$short_setting}
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
local bind_file="$(echo "$bind" | cut -d: -f2)"
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
@ -126,60 +126,9 @@ _ynh_app_config_apply_one() {
fi
fi
}
_ynh_app_config_get() {
# From settings
local lines
lines=$(
python3 <<EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
bind_panel = panel.get('bind')
for section_name, section in panel.items():
if not isinstance(section, dict): continue
bind_section = section.get('bind')
if not bind_section:
bind_section = bind_panel
elif bind_section[-1] == ":" and bind_panel and ":" in bind_panel:
regex, bind_panel_file = bind_panel.split(":")
if ">" in bind_section:
bind_section = bind_section + bind_panel_file
else:
bind_section = regex + bind_section + bind_panel_file
for name, param in section.items():
if not isinstance(param, dict):
continue
bind = param.get('bind')
if not bind:
if bind_section:
bind = bind_section
else:
bind = 'settings'
elif bind[-1] == ":" and bind_section and ":" in bind_section:
regex, bind_file = bind_section.split(":")
if ">" in bind:
bind = bind + bind_file
else:
bind = regex + bind + bind_file
if bind == "settings" and param.get('type', 'string') == 'file':
bind = 'null'
print('|'.join([
name,
param.get('type', 'string'),
bind
]))
EOL
)
for line in $lines; do
for line in $YNH_APP_CONFIG_PANEL_OPTIONS_TYPES_AND_BINDS; do
# Split line into short_setting, type and bind
IFS='|' read short_setting type bind <<< "$line"
binds[${short_setting}]="$bind"
@ -188,7 +137,6 @@ EOL
formats[${short_setting}]=""
ynh_app_config_get_one $short_setting $type $bind
done
}
_ynh_app_config_apply() {
@ -350,5 +298,6 @@ ynh_app_config_run() {
;;
*)
ynh_app_action_run $1
;;
esac
}

View file

@ -113,7 +113,7 @@ ignoreregex =
chown -R "$app:$app" "/var/log/$app"
chmod -R u=rwX,g=rX,o= "/var/log/$app"
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) fail2ban.service" --log_path=systemd
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
if [[ -n "$fail2ban_error" ]]; then

View file

@ -210,29 +210,24 @@ ynh_cleanup_go () {
# List required Go versions
local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_go_versions=""
for installed_app in $installed_apps
do
for installed_app in $installed_apps; do
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
if [[ $installed_app_go_version ]]
then
if [[ $installed_app_go_version ]]; then
required_go_versions="${installed_app_go_version}\n${required_go_versions}"
fi
done
# Remove no more needed Go versions
local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/')
for installed_go_version in $installed_go_versions
do
if ! `echo ${required_go_versions} | grep "${installed_go_version}" 1>/dev/null 2>&1`
then
for installed_go_version in $installed_go_versions; do
if ! $(echo ${required_go_versions} | grep "${installed_go_version}" 1> /dev/null 2>&1); then
ynh_print_info --message="Removing of Go-$installed_go_version"
$goenv_install_dir/bin/goenv uninstall --force "$installed_go_version"
fi
done
# If none Go version is required
if [[ ! $required_go_versions ]]
then
if [[ ! $required_go_versions ]]; then
# Remove goenv environment configuration
ynh_print_info --message="Removing of goenv"
ynh_secure_remove --file="$goenv_install_dir"

View file

@ -93,8 +93,7 @@ ynh_exec_err() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
ynh_print_err --message="$(eval $@)"
else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -114,8 +113,7 @@ ynh_exec_warn() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
ynh_print_warn --message="$(eval $@)"
else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -135,8 +133,7 @@ ynh_exec_warn_less() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
eval $@ 2>&1
else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -156,8 +153,7 @@ ynh_exec_quiet() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
eval $@ > /dev/null
else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -177,8 +173,7 @@ ynh_exec_fully_quiet() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
eval $@ > /dev/null 2>&1
else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077

View file

@ -17,10 +17,8 @@ ynh_use_logrotate() {
# Stupid patch to ignore legacy --non-append and --nonappend
# which was never properly understood and improperly used and kind of bullshit
local all_args=(${@})
for I in $(seq 0 $(($# - 1)))
do
if [[ "${all_args[$I]}" == "--non-append" ]] || [[ "${all_args[$I]}" == "--nonappend" ]]
then
for I in $(seq 0 $(($# - 1))); do
if [[ "${all_args[$I]}" == "--non-append" ]] || [[ "${all_args[$I]}" == "--nonappend" ]]; then
unset all_args[$I]
fi
done
@ -43,8 +41,7 @@ ynh_use_logrotate() {
fi
set +o noglob
for stuff in $logfile
do
for stuff in $logfile; do
mkdir --parents $(dirname "$stuff")
done
@ -76,8 +73,7 @@ $logfile {
}
EOF
if [[ "$FIRST_CALL_TO_LOGROTATE" == "true" ]]
then
if [[ "$FIRST_CALL_TO_LOGROTATE" == "true" ]]; then
cat $tempconf > /etc/logrotate.d/$app
else
cat $tempconf >> /etc/logrotate.d/$app

View file

@ -39,19 +39,16 @@ ynh_mongo_exec() {
eval=${eval:-0}
# If user is provided
if [ -n "$user" ]
then
if [ -n "$user" ]; then
user="--username=$user"
# If password is provided
if [ -n "$password" ]
then
if [ -n "$password" ]; then
password="--password=$password"
fi
# If authenticationdatabase is provided
if [ -n "$authenticationdatabase" ]
then
if [ -n "$authenticationdatabase" ]; then
authenticationdatabase="--authenticationDatabase=$authenticationdatabase"
else
authenticationdatabase="--authenticationDatabase=admin"
@ -62,23 +59,19 @@ ynh_mongo_exec() {
fi
# If host is provided
if [ -n "$host" ]
then
if [ -n "$host" ]; then
host="--host=$host"
fi
# If port is provided
if [ -n "$port" ]
then
if [ -n "$port" ]; then
port="--port=$port"
fi
# If eval is not provided
if [ $eval -eq 0 ]
then
if [ $eval -eq 0 ]; then
# If database is provided
if [ -n "$database" ]
then
if [ -n "$database" ]; then
database="use $database"
else
database=""
@ -91,8 +84,7 @@ quit()
EOF
else
# If database is provided
if [ -n "$database" ]
then
if [ -n "$database" ]; then
database="$database"
else
database=""
@ -186,8 +178,7 @@ ynh_mongo_database_exists() {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")' --eval) -lt 0 ]
then
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")' --eval) -lt 0 ]; then
return 1
else
return 0
@ -343,8 +334,7 @@ ynh_install_mongo() {
#
ynh_remove_mongo() {
# Only remove the mongodb service if it is not installed.
if ! ynh_package_is_installed --package="mongodb*"
then
if ! ynh_package_is_installed --package="mongodb*"; then
ynh_print_info --message="Removing MongoDB service..."
mongodb_servicename=mongod
# Remove the mongodb service

View file

@ -227,9 +227,6 @@ ynh_mysql_setup_db() {
# If $db_pwd is not provided, use new_db_pwd instead for 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_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd
}

View file

@ -43,7 +43,6 @@ ynh_remove_nginx_config() {
ynh_systemd_action --service_name=nginx --action=reload
}
# Regen the nginx config in a change url context
#
# usage: ynh_change_url_nginx_config

View file

@ -1,6 +1,6 @@
#!/bin/bash
readonly YNH_DEFAULT_PHP_VERSION=8.2
readonly YNH_DEFAULT_PHP_VERSION=7.4
# Declare the actual PHP version to use.
# 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}
@ -70,14 +70,17 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
ynh_add_fpm_config() {
local _globalphpversion=${phpversion-:}
# Declare an array to define the options of this helper.
local legacy_args=vufg
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [g]=group=)
local legacy_args=vufpdg
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service [g]=group=)
local group
local phpversion
local usage
local footprint
local package
local dedicated_service
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
package=${package:-}
group=${group:-}
# The default behaviour is to use the template.
@ -89,21 +92,21 @@ ynh_add_fpm_config() {
# If no usage provided, default to the value existing in setting ... or to low
local fpm_usage_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_usage)
if [ -z "$usage" ]
then
if [ -z "$usage" ]; then
usage=${fpm_usage_in_setting:-low}
ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage
fi
# If no footprint provided, default to the value existing in setting ... or to low
local fpm_footprint_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_footprint)
if [ -z "$footprint" ]
then
if [ -z "$footprint" ]; then
footprint=${fpm_footprint_in_setting:-low}
ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint
fi
fi
# Do not use a dedicated service by default
dedicated_service=${dedicated_service:-0}
# Set the default PHP-FPM version by default
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
@ -120,23 +123,51 @@ ynh_add_fpm_config() {
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
if [[ -f "$old_php_finalphpconf" ]]
then
if [[ -f "$old_php_finalphpconf" ]]; then
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
ynh_remove_fpm_config
fi
fi
# Legacy args (packager should just list their php dependency as regular apt dependencies...
if [ -n "$package" ]; then
# 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
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_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
# 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
# Usage 1, use the template in conf/php-fpm.conf
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
@ -190,6 +221,48 @@ pm.process_idle_timeout = 10s
local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then
ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead."
ynh_add_config --template="php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini"
fi
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
@ -197,6 +270,7 @@ pm.process_idle_timeout = 10s
ynh_die --message="The new configuration broke php-fpm?"
fi
ynh_systemd_action --service_name=$fpm_service --action=reload
fi
}
# Remove the dedicated PHP-FPM config
@ -207,6 +281,8 @@ pm.process_idle_timeout = 10s
ynh_remove_fpm_config() {
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 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
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
@ -220,7 +296,69 @@ ynh_remove_fpm_config() {
fi
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]; then
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

View file

@ -1,7 +1,7 @@
#!/bin/bash
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
PSQL_VERSION=15
PSQL_VERSION=13
# Open a connection as a user
#
@ -199,8 +199,7 @@ ynh_psql_database_exists() {
# if psql is not there, we cannot check the db
# though it could exists.
if ! command -v psql
then
if ! command -v psql; then
ynh_print_err -m "PostgreSQL is not installed, impossible to check for db existence."
return 1
elif ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then

View file

@ -13,10 +13,8 @@ ynh_redis_get_free_db() {
db=0
# default Debian setting is 15 databases
for i in $(seq 0 "$max")
do
if ! echo "$result" | grep -q "db$i"
then
for i in $(seq 0 "$max"); do
if ! echo "$result" | grep -q "db$i"; then
db=$i
break 1
fi

View file

@ -210,8 +210,7 @@ ynh_install_ruby () {
ynh_app_setting_set --app=$app --key=ruby_version --value=$final_ruby_version
# Remove app virtualenv
if rbenv alias --list | grep --quiet "$app "
then
if rbenv alias --list | grep --quiet "$app "; then
rbenv alias $app --remove
fi
@ -267,29 +266,24 @@ ynh_cleanup_ruby () {
# List required Ruby versions
local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$')
local required_ruby_versions=""
for installed_app in $installed_apps
do
for installed_app in $installed_apps; do
local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version")
if [[ -n "$installed_app_ruby_version" ]]
then
if [[ -n "$installed_app_ruby_version" ]]; then
required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}"
fi
done
# Remove no more needed Ruby versions
local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/')
for installed_ruby_version in $installed_ruby_versions
do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"
then
for installed_ruby_version in $installed_ruby_versions; do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"; then
ynh_print_info --message="Removing Ruby-$installed_ruby_version"
$rbenv_install_dir/bin/rbenv uninstall --force $installed_ruby_version
fi
done
# If none Ruby version is required
if [[ -z "$required_ruby_versions" ]]
then
if [[ -z "$required_ruby_versions" ]]; then
# Remove rbenv environment configuration
ynh_print_info --message="Removing rbenv"
ynh_secure_remove --file="$rbenv_install_dir"

View file

@ -18,7 +18,11 @@ ynh_app_setting_get() {
ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}"
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then
yunohost app setting $app $key
else
ynh_app_setting "get" "$app" "$key"
fi
}
# Set an application setting
@ -41,7 +45,11 @@ ynh_app_setting_set() {
ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}"
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then
yunohost app setting $app $key -v $value
else
ynh_app_setting "set" "$app" "$key" "$value"
fi
}
# Set an application setting but only if the "$key" variable ain't set yet
@ -98,7 +106,11 @@ ynh_app_setting_delete() {
ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}"
if [[ "$key" =~ (unprotected|skipped|protected)_ ]]; then
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

View file

@ -77,12 +77,10 @@ ynh_setup_source() {
keep="${keep:-}"
full_replace="${full_replace:-0}"
if test -e $YNH_APP_BASEDIR/manifest.toml && cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq -e '.resources.sources' >/dev/null
then
if test -e $YNH_APP_BASEDIR/manifest.toml && cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq -e '.resources.sources' > /dev/null; then
source_id="${source_id:-main}"
local sources_json=$(cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq ".resources.sources[\"$source_id\"]")
if jq -re ".url" <<< "$sources_json"
then
if jq -re ".url" <<< "$sources_json"; then
local arch_prefix=""
else
local arch_prefix=".$YNH_ARCH"
@ -100,22 +98,16 @@ ynh_setup_source() {
[[ -n "$src_url" ]] || ynh_die "No URL defined for source $source_id$arch_prefix ?"
[[ -n "$src_sum" ]] || ynh_die "No sha256 sum defined for source $source_id$arch_prefix ?"
if [[ -z "$src_format" ]]
then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]
then
if [[ -z "$src_format" ]]; then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]; then
src_format="zip"
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]; then
src_format="tar.gz"
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]; then
src_format="tar.xz"
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]; then
src_format="tar.bz2"
elif [[ -z "$src_extract" ]]
then
elif [[ -z "$src_extract" ]]; then
src_extract="false"
fi
fi
@ -142,12 +134,10 @@ ynh_setup_source() {
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
src_extract=${src_extract:-true}
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]
then
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]; then
ynh_die "For source $source_id, expected either 'true' or 'false' for the extract parameter"
fi
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${source_id}"
@ -165,14 +155,12 @@ ynh_setup_source() {
[ -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 [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
if [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status; then
rm -f "$src_filename"
fi
# Only redownload the file if it wasnt prefetched
if [ ! -e "$src_filename" ]
then
if [ ! -e "$src_filename" ]; then
# NB. we have to declare the var as local first,
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
# because local always return 0 ...
@ -183,8 +171,7 @@ ynh_setup_source() {
fi
# Check the control sum
if ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
if ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status; then
local actual_sum="$(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)"
local actual_size="$(du -hs ${src_filename} | cut --fields=1)"
rm -f ${src_filename}
@ -222,8 +209,7 @@ ynh_setup_source() {
fi
if [[ "$src_extract" == "false" ]]; then
if [[ -z "$src_rename" ]]
then
if [[ -z "$src_rename" ]]; then
mv $src_filename $dest_dir
else
mv $src_filename $dest_dir/$src_rename

View file

@ -149,8 +149,7 @@ ynh_systemd_action() {
# Also check the timeout using actual timestamp, because sometimes for some reason,
# journalctl may take a huge time to run, and we end up waiting literally an entire hour
# instead of 5 min ...
if [[ "$(( $(date +%s) - $starttime))" -gt "$timeout" ]]
then
if [[ "$(($(date +%s) - $starttime))" -gt "$timeout" ]]; then
i=$timeout
break
fi

View file

@ -83,8 +83,7 @@ ynh_add_config() {
chmod 640 $destination
_ynh_apply_default_permissions $destination
if [[ "$jinja" == 1 ]]
then
if [[ "$jinja" == 1 ]]; then
# This is ran in a subshell such that the "export" does not "contaminate" the main process
(
export $(compgen -v)

View file

@ -22,8 +22,7 @@ YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
ynh_exit_properly() {
local exit_code=$?
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]
then
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]; then
rm -rf "/var/cache/yunohost/download/"
fi
@ -67,8 +66,7 @@ ynh_abort_if_errors() {
}
# When running an app script with packaging format >= 2, auto-enable ynh_abort_if_errors except for remove script
if [[ "${YNH_CONTEXT:-}" != "regenconf" ]] && dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} ge 2 && [[ ${YNH_APP_ACTION} != "remove" ]]
then
if [[ "${YNH_CONTEXT:-}" != "regenconf" ]] && dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} ge 2 && [[ ${YNH_APP_ACTION} != "remove" ]]; then
ynh_abort_if_errors
fi
@ -149,8 +147,7 @@ _acceptable_path_to_delete() {
local forbidden_paths=$(ls -d / /* /{var,home,usr}/* /etc/{default,sudoers.d,yunohost,cron*} /etc/yunohost/{apps,domains,hooks.d} /opt/yunohost 2> /dev/null)
# Legacy : A couple apps still have data in /home/$app ...
if [[ -n "${app:-}" ]]
then
if [[ -n "${app:-}" ]]; then
forbidden_paths=$(echo "$forbidden_paths" | grep -v "/home/$app")
fi
@ -215,19 +212,16 @@ ynh_read_manifest() {
if [ ! -e "${manifest:-}" ]; then
# If the manifest isn't found, try the common place for backup and restore script.
if [ -e "$YNH_APP_BASEDIR/manifest.json" ]
then
if [ -e "$YNH_APP_BASEDIR/manifest.json" ]; then
manifest="$YNH_APP_BASEDIR/manifest.json"
elif [ -e "$YNH_APP_BASEDIR/manifest.toml" ]
then
elif [ -e "$YNH_APP_BASEDIR/manifest.toml" ]; then
manifest="$YNH_APP_BASEDIR/manifest.toml"
else
ynh_die --message "No manifest found !?"
fi
fi
if echo "$manifest" | grep -q '\.json$'
then
if echo "$manifest" | grep -q '\.json$'; then
jq ".$manifest_key" "$manifest" --raw-output
else
cat "$manifest" | python3 -c 'import json, toml, sys; print(json.dumps(toml.load(sys.stdin)))' | jq ".$manifest_key" --raw-output
@ -373,25 +367,28 @@ ynh_compare_current_package_version() {
_ynh_apply_default_permissions() {
local target=$1
local ynh_requirement=$(ynh_read_manifest --manifest_key="requirements.yunohost" | tr -d '<>= ')
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} ge 2 || [ -z "$ynh_requirement" ] || [ "$ynh_requirement" == "null" ] || dpkg --compare-versions $ynh_requirement ge 4.2; then
chmod o-rwx $target
chmod g-w $target
chown -R root:root $target
if ynh_system_user_exists $app; then
chown $app:$app $target
fi
fi
# Crons should be owned by root
# Also we don't want systemd conf, nginx conf or others stuff to be owned by the app,
# otherwise they could self-edit their own systemd conf and escalate privilege
if grep -qE '^(/etc/cron|/etc/php|/etc/nginx/conf.d|/etc/fail2ban|/etc/systemd/system)' <<< "$target"
then
if grep -qE '^(/etc/cron|/etc/php|/etc/nginx/conf.d|/etc/fail2ban|/etc/systemd/system)' <<< "$target"; then
chmod 400 $target
chown root:root $target
fi
}
int_to_bool() {
sed -e 's/^1$/True/g' -e 's/^0$/False/g' -e 's/^true$/True/g' -e 's/^false$/False/g'
sed -e 's/^1$/True/g' -e 's/^0$/False/g'
}
toml_to_json() {

View file

@ -4,9 +4,9 @@ YNH_APT_INSTALL_DEPENDENCIES_REPLACE="true"
# Define and install dependencies with a equivs control file
#
# example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
# example : ynh_apt_install_dependencies dep1 dep2 "dep3|dep4|dep5"
#
# usage: ynh_install_app_dependencies dep [dep [...]]
# usage: ynh_apt_install_dependencies dep [dep [...]]
# | arg: dep - the package name to install in dependence.
# | arg: "dep1|dep2|…" - You can specify alternatives. It will require to install (dep1 or dep2, etc).
#
@ -39,8 +39,7 @@ ynh_apt_install_dependencies() {
# The (?<=php) syntax corresponds to lookbehind ;)
local specific_php_version=$(grep -oP '(?<=php)[0-9.]+(?=-|\>|)' <<< "$dependencies" | sort -u)
if [[ -n "$specific_php_version" ]]
then
if [[ -n "$specific_php_version" ]]; then
# Cover a small edge case where a packager could have specified "php7.4-pwet php5-gni" which is confusing
[[ $(echo $specific_php_version | wc -l) -eq 1 ]] \
|| ynh_die "Inconsistent php versions in dependencies ... found : $specific_php_version"
@ -51,8 +50,7 @@ ynh_apt_install_dependencies() {
# If the PHP version changed, remove the old fpm conf
if [ -n "$old_php_version" ] && [ "$old_php_version" != "$specific_php_version" ]; then
if [[ -f "/etc/php/$php_version/fpm/pool.d/$app.conf" ]]
then
if [[ -f "/etc/php/$php_version/fpm/pool.d/$app.conf" ]]; then
ynh_backup_if_checksum_is_different "/etc/php/$php_version/fpm/pool.d/$app.conf"
ynh_config_remove_phpfpm
fi
@ -61,8 +59,7 @@ ynh_apt_install_dependencies() {
ynh_app_setting_set --key=php_version --value=$specific_php_version
# Set the default php version back as the default version for php-cli.
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
then
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION; then
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
fi
elif grep --quiet 'php' <<< "$dependencies"; then
@ -72,18 +69,16 @@ ynh_apt_install_dependencies() {
# Specific tweak related to Postgresql (cf end of the helper)
local psql_installed="$(_ynh_apt_package_is_installed "postgresql-$PSQL_VERSION" && echo yes || echo no)"
# The first time we run ynh_install_app_dependencies, we will replace the
# The first time we run ynh_apt_install_dependencies, we will replace the
# entire control file (This is in particular meant to cover the case of
# upgrade script where ynh_install_app_dependencies is called with this
# upgrade script where ynh_apt_install_dependencies is called with this
# expected effect) Otherwise, any subsequent call will add dependencies
# to those already present in the equivs control file.
if [[ $YNH_APT_INSTALL_DEPENDENCIES_REPLACE == "true" ]]
then
if [[ $YNH_APT_INSTALL_DEPENDENCIES_REPLACE == "true" ]]; then
YNH_APT_INSTALL_DEPENDENCIES_REPLACE="false"
else
local current_dependencies=""
if _ynh_apt_package_is_installed "${app_ynh_deps}"
then
if _ynh_apt_package_is_installed "${app_ynh_deps}"; then
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${app_ynh_deps}) "
current_dependencies=${current_dependencies// | /|}
fi
@ -145,8 +140,7 @@ EOF
# Specific tweak related to Postgresql
# -> trigger postgresql regenconf if we may have just installed postgresql
local psql_installed2="$(_ynh_apt_package_is_installed "postgresql-$PSQL_VERSION" && echo yes || echo no)"
if [[ "$psql_installed" != "$psql_installed2" ]]
then
if [[ "$psql_installed" != "$psql_installed2" ]]; then
yunohost tools regen-conf postgresql
fi
@ -168,16 +162,14 @@ ynh_apt_remove_dependencies() {
# Edge case where the app dep may be on hold,
# cf https://forum.yunohost.org/t/migration-error-cause-of-ffsync/20675/4
if apt-mark showhold | grep -q -w ${app_ynh_deps}
then
if apt-mark showhold | grep -q -w ${app_ynh_deps}; then
apt-mark unhold ${app_ynh_deps}
fi
# Remove the fake package and its dependencies if they not still used.
# (except if dpkg doesn't know anything about the package,
# which should be symptomatic of a failed install, and we don't want bash to report an error)
if dpkg-query --show ${app_ynh_deps} &>/dev/null
then
if dpkg-query --show ${app_ynh_deps} &> /dev/null; then
_ynh_apt autoremove --purge ${app_ynh_deps}
fi
}
@ -206,8 +198,10 @@ ynh_apt_install_dependencies_from_extra_repository() {
if [[ "${repo_parts[0]}" == "deb" ]]; then
index=1
fi
uri="${repo_parts[$index]}" ; index=$((index+1))
suite="${repo_parts[$index]}" ; index=$((index+1))
uri="${repo_parts[$index]}"
index=$((index + 1))
suite="${repo_parts[$index]}"
index=$((index + 1))
# Get the components
if (("${#repo_parts[@]}" > 0)); then

View file

@ -27,13 +27,11 @@ ynh_backup() {
local is_data=false
# If the path starts with /var/log/$app or $data_dir
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]])
then
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]]); then
is_data=true
fi
if [[ -n "${app:-}" ]]
then
if [[ -n "${app:-}" ]]; then
local do_not_backup_data=$(ynh_app_setting_get --key=do_not_backup_data)
fi
@ -135,15 +133,13 @@ ynh_restore() {
# If the path starts with /var/log/$app or $data_dir
local is_data=false
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]])
then
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]]); then
is_data=true
fi
# If archive_path doesn't exist, search for a corresponding path in CSV
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
if [[ "$is_data" == true ]]
then
if [[ "$is_data" == true ]]; then
ynh_print_info "Skipping $target which doesn't exists in the archive, probably because restoring from a safety-backup-before-upgrade"
# Assume it's not a big deal, we may be restoring a safety-backup-before-upgrade which doesnt contain those
return 0
@ -194,7 +190,7 @@ ynh_restore_everything() {
# For each destination path begining by $REL_DIR
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" \
| while read line; do
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\"$REL_DIR.*\"$)")
ynh_restore "$ARCHIVE_PATH"
done
}
@ -256,8 +252,7 @@ ynh_backup_if_checksum_is_different() {
echo "$backup_file_checksum" # Return the name of the backup file
if ynh_in_ci_tests; then
local file_path_base64=$(echo "$file" | base64 -w0)
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}
then
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}; then
ynh_print_warn "Diff with the original file:"
diff --report-identical-files --unified --color=always /var/cache/yunohost/appconfbackup/original_${file_path_base64} $file >&2 || true
fi

View file

@ -22,7 +22,7 @@ _ynh_app_config_get_one() {
if [[ "$bind" == "settings" ]]; then
ynh_die "File '${short_setting}' can't be stored in settings"
fi
old[$short_setting]="$(ls "$(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)" 2>/dev/null || echo YNH_NULL)"
old[$short_setting]="$(ls "$bind" 2> /dev/null || echo YNH_NULL)"
file_hash[$short_setting]="true"
# Get multiline text from settings or from a full file
@ -32,7 +32,7 @@ _ynh_app_config_get_one() {
elif [[ "$bind" == *":"* ]]; then
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else
old[$short_setting]="$(cat $(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
old[$short_setting]="$(cat "$bind" 2> /dev/null || echo YNH_NULL)"
fi
# Get value from a kind of key/value file
@ -47,7 +47,7 @@ _ynh_app_config_get_one() {
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
local bind_file="$(echo "$bind" | cut -d: -f2)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
fi
@ -73,7 +73,7 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == "settings" ]]; then
ynh_die "File '${short_setting}' can't be stored in settings"
fi
local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
local bind_file="$bind"
if [[ "${!short_setting}" == "" ]]; then
ynh_backup_if_checksum_is_different "$bind_file"
ynh_safe_rm "$bind_file"
@ -84,8 +84,7 @@ _ynh_app_config_apply_one() {
if [[ "${!short_setting}" != "$bind_file" ]]; then
cp "${!short_setting}" "$bind_file"
fi
if _ynh_file_checksum_exists "$bind_file"
then
if _ynh_file_checksum_exists "$bind_file"; then
ynh_store_file_checksum "$bind_file"
fi
ynh_print_info "File '$bind_file' overwritten with ${!short_setting}"
@ -101,11 +100,10 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == *":"* ]]; then
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
fi
local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
local bind_file="$bind"
ynh_backup_if_checksum_is_different "$bind_file"
echo "${!short_setting}" > "$bind_file"
if _ynh_file_checksum_exists "$bind_file"
then
if _ynh_file_checksum_exists "$bind_file"; then
ynh_store_file_checksum "$bind_file"
fi
ynh_print_info "File '$bind_file' overwritten with the content provided in question '${short_setting}'"
@ -119,12 +117,11 @@ _ynh_app_config_apply_one() {
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
bind_key_=${bind_key_:-$short_setting}
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
local bind_file="$(echo "$bind" | cut -d: -f2)"
ynh_backup_if_checksum_is_different "$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
if _ynh_file_checksum_exists "$bind_file"
then
if _ynh_file_checksum_exists "$bind_file"; then
ynh_store_file_checksum "$bind_file"
fi
@ -135,60 +132,9 @@ _ynh_app_config_apply_one() {
fi
fi
}
_ynh_app_config_get() {
# From settings
local lines
lines=$(
python3 <<EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
bind_panel = panel.get('bind')
for section_name, section in panel.items():
if not isinstance(section, dict): continue
bind_section = section.get('bind')
if not bind_section:
bind_section = bind_panel
elif bind_section[-1] == ":" and bind_panel and ":" in bind_panel:
regex, bind_panel_file = bind_panel.split(":")
if ">" in bind_section:
bind_section = bind_section + bind_panel_file
else:
bind_section = regex + bind_section + bind_panel_file
for name, param in section.items():
if not isinstance(param, dict):
continue
bind = param.get('bind')
if not bind:
if bind_section:
bind = bind_section
else:
bind = 'settings'
elif bind[-1] == ":" and bind_section and ":" in bind_section:
regex, bind_file = bind_section.split(":")
if ">" in bind:
bind = bind + bind_file
else:
bind = regex + bind + bind_file
if bind == "settings" and param.get('type', 'string') == 'file':
bind = 'null'
print('|'.join([
name,
param.get('type', 'string'),
bind
]))
EOL
)
for line in $lines; do
for line in $YNH_APP_CONFIG_PANEL_OPTIONS_TYPES_AND_BINDS; do
# Split line into short_setting, type and bind
IFS='|' read short_setting type bind <<< "$line"
binds[${short_setting}]="$bind"
@ -197,7 +143,6 @@ EOL
formats[${short_setting}]=""
ynh_app_config_get_one $short_setting $type $bind
done
}
_ynh_app_config_apply() {
@ -359,5 +304,6 @@ ynh_app_config_run() {
;;
*)
ynh_app_action_run $1
;;
esac
}

View file

@ -50,8 +50,7 @@ ynh_handle_getopts_args() {
eval "$xtrace_enable"
return
# Validate that the first char is - because it should be something like --option=value or -o ...
elif [[ "${1:0:1}" != "-" ]]
then
elif [[ "${1:0:1}" != "-" ]]; then
ynh_die "It looks like you called the helper using positional arguments instead of keyword arguments ?"
fi

View file

@ -156,29 +156,24 @@ _ynh_go_cleanup () {
# List required Go versions
local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_go_versions=""
for installed_app in $installed_apps
do
for installed_app in $installed_apps; do
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
if [[ $installed_app_go_version ]]
then
if [[ $installed_app_go_version ]]; then
required_go_versions="${installed_app_go_version}\n${required_go_versions}"
fi
done
# Remove no more needed Go versions
local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/')
for installed_go_version in $installed_go_versions
do
if ! `echo ${required_go_versions} | grep "${installed_go_version}" 1>/dev/null 2>&1`
then
for installed_go_version in $installed_go_versions; do
if ! $(echo ${required_go_versions} | grep "${installed_go_version}" 1> /dev/null 2>&1); then
ynh_print_info "Removing of Go-$installed_go_version"
$GOENV_INSTALL_DIR/bin/goenv uninstall --force "$installed_go_version"
fi
done
# If none Go version is required
if [[ ! $required_go_versions ]]
then
if [[ ! $required_go_versions ]]; then
# Remove goenv environment configuration
ynh_print_info "Removing of goenv"
ynh_safe_rm "$GOENV_INSTALL_DIR"

View file

@ -5,10 +5,8 @@
# usage: ynh_die "Some message"
ynh_die() {
set +o xtrace # set +x
if [[ -n "${1:-}" ]]
then
if [[ -n "${YNH_STDRETURN:-}" ]]
then
if [[ -n "${1:-}" ]]; then
if [[ -n "${YNH_STDRETURN:-}" ]]; then
python3 -c 'import yaml, sys; print(yaml.dump({"error": sys.stdin.read()}))' <<< "${1:-}" >> "$YNH_STDRETURN"
fi
echo "${1:-}" 1>&2
@ -105,8 +103,7 @@ ynh_script_progression() {
local expected_progression="$((($increment_progression + 1) * $progress_scale / $max_progression - $effective_progression))"
# Hack for the "--last" message
if grep -qw 'completed' <<< "$1";
then
if grep -qw 'completed' <<< "$1"; then
effective_progression=$progress_scale
expected_progression=0
fi

View file

@ -22,8 +22,7 @@ ynh_config_add_logrotate() {
fi
set +o noglob
for stuff in $logfile
do
for stuff in $logfile; do
# Make sure the permissions of the parent dir are correct (otherwise the config file could be ignored and the corresponding logs never rotated)
local dir=$(dirname "$stuff")
mkdir --parents $dir
@ -53,8 +52,7 @@ $logfile {
}
EOF
if [[ "$FIRST_CALL_TO_LOGROTATE" == "true" ]]
then
if [[ "$FIRST_CALL_TO_LOGROTATE" == "true" ]]; then
cat $tempconf > /etc/logrotate.d/$app
else
cat $tempconf >> /etc/logrotate.d/$app

View file

@ -19,8 +19,7 @@ ynh_mongo_exec() {
database="${database:-}"
# ===========================================
if [ -n "$database" ]
then
if [ -n "$database" ]; then
mongosh --quiet << EOF
use $database
${command}
@ -111,8 +110,7 @@ ynh_mongo_database_exists() {
ynh_handle_getopts_args "$@"
# ===========================================
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")') -lt 0 ]
then
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")') -lt 0 ]; then
return 1
else
return 0
@ -262,8 +260,7 @@ ynh_install_mongo() {
#
ynh_remove_mongo() {
# Only remove the mongodb service if it is not installed.
if ! _ynh_apt_package_is_installed "mongodb*"
then
if ! _ynh_apt_package_is_installed "mongodb*"; then
ynh_print_info "Removing MongoDB service..."
mongodb_servicename=mongod
# Remove the mongodb service

View file

@ -39,7 +39,6 @@ ynh_config_remove_nginx() {
ynh_systemctl --service=nginx --action=reload
}
# Regen the nginx config in a change url context
#
# usage: ynh_config_change_url_nginx

View file

@ -13,10 +13,8 @@ ynh_redis_get_free_db() {
db=0
# default Debian setting is 15 databases
for i in $(seq 0 "$max")
do
if ! echo "$result" | grep -q "db$i"
then
for i in $(seq 0 "$max"); do
if ! echo "$result" | grep -q "db$i"; then
db=$i
break 1
fi

View file

@ -153,8 +153,7 @@ ynh_ruby_install () {
ruby_version=$final_ruby_version
# Remove app virtualenv
if rbenv alias --list | grep --quiet "$app "
then
if rbenv alias --list | grep --quiet "$app "; then
rbenv alias $app --remove
fi
@ -213,29 +212,24 @@ _ynh_ruby_cleanup () {
# List required Ruby versions
local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$')
local required_ruby_versions=""
for installed_app in $installed_apps
do
for installed_app in $installed_apps; do
local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version")
if [[ -n "$installed_app_ruby_version" ]]
then
if [[ -n "$installed_app_ruby_version" ]]; then
required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}"
fi
done
# Remove no more needed Ruby versions
local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/')
for installed_ruby_version in $installed_ruby_versions
do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"
then
for installed_ruby_version in $installed_ruby_versions; do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"; then
echo "Removing Ruby-$installed_ruby_version"
$RBENV_INSTALL_DIR/bin/rbenv uninstall --force $installed_ruby_version
fi
done
# If none Ruby version is required
if [[ -z "$required_ruby_versions" ]]
then
if [[ -z "$required_ruby_versions" ]]; then
# Remove rbenv environment configuration
echo "Removing rbenv"
ynh_safe_rm "$RBENV_INSTALL_DIR"

View file

@ -125,15 +125,11 @@ EOF
# Legacy: auto-convert phpversion to php_version (for consistency with nodejs_version, ruby_version, ...)
# This has to be here and not in the "php" code file because ynh_app_setting_set/delete need to be defined @_@
if [[ -n "${app:-}" ]] && [[ -n "${phpversion:-}" ]]
then
if [[ -z "${php_version:-}" ]]
then
if [[ -n "${app:-}" ]] && [[ -n "${phpversion:-}" ]]; then
if [[ -z "${php_version:-}" ]]; then
php_version=$phpversion
ynh_app_setting_set --key=php_version --value=$php_version
fi
ynh_app_setting_delete --key=phpversion
unset phpversion
fi

View file

@ -74,8 +74,7 @@ ynh_setup_source() {
# ===========================================
local sources_json=$(ynh_read_manifest "resources.sources[\"$source_id\"]")
if jq -re ".url" <<< "$sources_json"
then
if jq -re ".url" <<< "$sources_json"; then
local arch_prefix=""
else
local arch_prefix=".$YNH_ARCH"
@ -93,25 +92,18 @@ ynh_setup_source() {
[[ -n "$src_url" ]] || ynh_die "No URL defined for source $source_id$arch_prefix ?"
[[ -n "$src_sum" ]] || ynh_die "No sha256 sum defined for source $source_id$arch_prefix ?"
if [[ -z "$src_format" ]]
then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]
then
if [[ -z "$src_format" ]]; then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]; then
src_format="zip"
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]; then
src_format="tar.gz"
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]; then
src_format="tar.xz"
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]; then
src_format="tar.bz2"
elif [[ "$src_url" =~ ^.*\.tar$ ]]
then
elif [[ "$src_url" =~ ^.*\.tar$ ]]; then
src_format="tar"
elif [[ -z "$src_extract" ]]
then
elif [[ -z "$src_extract" ]]; then
src_extract="false"
fi
fi
@ -120,8 +112,7 @@ ynh_setup_source() {
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
src_extract=${src_extract:-true}
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]
then
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]; then
ynh_die "For source $source_id, expected either 'true' or 'false' for the extract parameter"
fi
@ -135,14 +126,12 @@ ynh_setup_source() {
[ -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 [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | sha256sum --check --status
then
if [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | sha256sum --check --status; then
rm -f "$src_filename"
fi
# Only redownload the file if it wasnt prefetched
if [ ! -e "$src_filename" ]
then
if [ ! -e "$src_filename" ]; then
# NB. we have to declare the var as local first,
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
# because local always return 0 ...
@ -153,8 +142,7 @@ ynh_setup_source() {
fi
# Check the control sum
if ! echo "${src_sum} ${src_filename}" | sha256sum --check --status
then
if ! echo "${src_sum} ${src_filename}" | sha256sum --check --status; then
local actual_sum="$(sha256sum ${src_filename} | cut --delimiter=' ' --fields=1)"
local actual_size="$(du -hs ${src_filename} | cut --fields=1)"
rm -f ${src_filename}
@ -185,8 +173,7 @@ ynh_setup_source() {
mkdir --parents "$dest_dir"
if [[ "$src_extract" == "false" ]]; then
if [[ -z "$src_rename" ]]
then
if [[ -z "$src_rename" ]]; then
mv $src_filename $dest_dir
else
mv $src_filename $dest_dir/$src_rename
@ -224,8 +211,8 @@ ynh_setup_source() {
fi
# Apply patches
if [ -d "$YNH_APP_BASEDIR/patches/" ]; then
local patches_folder=$(realpath "$YNH_APP_BASEDIR/patches/$source_id")
if [ -d "$patches_folder" ]; then
pushd "$dest_dir"
for patchfile in "$patches_folder/"*.patch; do
echo "Applying $patchfile"

View file

@ -68,8 +68,7 @@ ynh_systemctl() {
# ===========================================
# On CI, use length=100 because it's sometime hell to debug otherwise for super-long output
if ynh_in_ci_tests && [ $length -le 20 ]
then
if ynh_in_ci_tests && [ $length -le 20 ]; then
length=100
fi
@ -139,8 +138,7 @@ ynh_systemctl() {
# Also check the timeout using actual timestamp, because sometimes for some reason,
# journalctl may take a huge time to run, and we end up waiting literally an entire hour
# instead of 5 min ...
if [[ "$(( $(date +%s) - $starttime))" -gt "$timeout" ]]
then
if [[ "$(($(date +%s) - $starttime))" -gt "$timeout" ]]; then
i=$timeout
break
fi
@ -160,8 +158,7 @@ ynh_systemctl() {
fi
# If we tried to reload/start/restart the service but systemctl consider it to be still inactive/broken, then handle it as a failure
if ([ "$action" == "reload" ] || [ "$action" == "start" ] || [ "$action" == "restart" ]) && ! systemctl --quiet is-active $service
then
if ([ "$action" == "reload" ] || [ "$action" == "start" ] || [ "$action" == "restart" ]) && ! systemctl --quiet is-active $service; then
_ynh_clean_check_starting
return 1
fi

View file

@ -70,8 +70,7 @@ ynh_config_add() {
chmod 640 $destination
_ynh_apply_default_permissions $destination
if [[ "$jinja" == 1 ]]
then
if [[ "$jinja" == 1 ]]; then
# This is ran in a subshell such that the "export" does not "contaminate" the main process
(
export $(compgen -v)

View file

@ -9,8 +9,7 @@ YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
ynh_exit_properly() {
local exit_code=$?
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]
then
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]; then
rm -rf "/var/cache/yunohost/download/"
fi
@ -47,8 +46,7 @@ ynh_abort_if_errors() {
}
# When running an app script, auto-enable ynh_abort_if_errors except for remove script
if [[ "${YNH_CONTEXT:-}" != "regenconf" ]] && [[ "${YNH_APP_ACTION}" != "remove" ]]
then
if [[ "${YNH_CONTEXT:-}" != "regenconf" ]] && [[ "${YNH_APP_ACTION}" != "remove" ]]; then
ynh_abort_if_errors
fi
@ -124,8 +122,7 @@ _acceptable_path_to_delete() {
local forbidden_paths=$(ls -d / /* /{var,home,usr}/* /etc/{default,sudoers.d,yunohost,cron*} /etc/yunohost/{apps,domains,hooks.d} /opt/yunohost 2> /dev/null)
# Legacy : A couple apps still have data in /home/$app ...
if [[ -n "${app:-}" ]]
then
if [[ -n "${app:-}" ]]; then
forbidden_paths=$(echo "$forbidden_paths" | grep -v "/home/$app")
fi
@ -231,23 +228,19 @@ _ynh_apply_default_permissions() {
# App files can have files of their own
if ynh_system_user_exists --username="$app"; then
# If this is a file in $install_dir or $data_dir : it should be owned and read+writable by $app only
if [ -f "$target" ] && (is_in_dir "$target" "${install_dir:-}" || is_in_dir "$target" "${data_dir:-}" || is_in_dir "$target" "/etc/$app")
then
if [ -f "$target" ] && (is_in_dir "$target" "${install_dir:-}" || is_in_dir "$target" "${data_dir:-}" || is_in_dir "$target" "/etc/$app"); then
chmod 600 "$target"
chown "$app:$app" "$target"
return
fi
# If this is the install dir (so far this is the only way this helper is called with a directory)
if [ "$target" == "${install_dir:-}" ]
then
if [ "$target" == "${install_dir:-}" ]; then
# Read the group from the install_dir manifest resource
local group="$(ynh_read_manifest 'resources.install_dir.group' | sed 's/null//g' | sed "s/__APP__/$app/g" | cut -f1 -d:)"
if [[ -z "$group" ]]
then
if [[ -z "$group" ]]; then
# We set the group to www-data for webapps that do serve static assets, which therefore need to be readable by nginx ...
# The fact that the app needs this is infered by the existence of an nginx.conf and the presence of "alias" or "root" directive
if grep -q '^\s*alias\s\|^\s*root\s' "$YNH_APP_BASEDIR/conf/nginx.conf" 2>/dev/null;
then
if grep -q '^\s*alias\s\|^\s*root\s' "$YNH_APP_BASEDIR/conf/nginx.conf" 2> /dev/null; then
group="www-data"
# Or default to "$app"
else
@ -407,41 +400,37 @@ ynh_spawn_app_shell() {
# Load the app's service name, or default to $app
local service=$(ynh_app_setting_get --app=$app --key=service)
[ -z "$service" ] && service=$app;
[ -z "$service" ] && service=$app
# Export HOME variable
export HOME=$install_dir;
export HOME=$install_dir
# Load the Environment variables from the app's service
local env_var=$(systemctl show $service.service -p "Environment" --value)
[ -n "$env_var" ] && export $env_var;
[ -n "$env_var" ] && export $env_var
# Force `php` to its intended version
# 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 phpflags=$(ynh_app_setting_get --app=$app --key=phpflags)
if [ -n "$phpversion" ]
then
if [ -n "$phpversion" ]; then
eval "php() { php${phpversion} ${phpflags} \"\$@\"; }"
export -f php
fi
# Source the EnvironmentFiles from the app's service
local env_files=($(systemctl show $service.service -p "EnvironmentFiles" --value))
if [ ${#env_files[*]} -gt 0 ]
then
if [ ${#env_files[*]} -gt 0 ]; then
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
set -a
for file in ${env_files[*]}
do
for file in ${env_files[*]}; do
[[ $file = /* ]] && source $file
done
set +a
fi
# Activate the Python environment, if it exists
if [ -f $install_dir/venv/bin/activate ]
then
if [ -f $install_dir/venv/bin/activate ]; then
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
set -a
source $install_dir/venv/bin/activate
@ -450,9 +439,145 @@ ynh_spawn_app_shell() {
# cd into the WorkingDirectory set in the service, or default to the install_dir
local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value)
[ -z $env_dir ] && env_dir=$install_dir;
[ -z $env_dir ] && env_dir=$install_dir
cd $env_dir
# Spawn the app shell
su -s /bin/bash $app
}
# Add swap
#
# usage: ynh_add_swap --size=SWAP in Mb
# | arg: -s, --size= - Amount of SWAP to add in Mb.
ynh_add_swap() {
if systemd-detect-virt --container --quiet; then
ynh_print_warn --message="You are inside a container/VM. swap will not be added, but that can cause troubles for the app $app. Please make sure you have enough RAM available."
return
fi
# Declare an array to define the options of this helper.
declare -Ar args_array=([s]=size=)
local size
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local swap_max_size=$(($size * 1024))
local free_space=$(df --output=avail / | sed 1d)
# Because we don't want to fill the disk with a swap file, divide by 2 the available space.
local usable_space=$(($free_space / 2))
SD_CARD_CAN_SWAP=${SD_CARD_CAN_SWAP:-0}
# Swap on SD card only if it's is specified
if ynh_is_main_device_a_sd_card && [ "$SD_CARD_CAN_SWAP" == "0" ]; then
ynh_print_warn --message="The main mountpoint of your system '/' is on an SD card, swap will not be added to prevent some damage of this one, but that can cause troubles for the app $app. If you still want activate the swap, you can relaunch the command preceded by 'SD_CARD_CAN_SWAP=1'"
return
fi
# Compare the available space with the size of the swap.
# And set a acceptable size from the request
if [ $usable_space -ge $swap_max_size ]; then
local swap_size=$swap_max_size
elif [ $usable_space -ge $(($swap_max_size / 2)) ]; then
local swap_size=$(($swap_max_size / 2))
elif [ $usable_space -ge $(($swap_max_size / 3)) ]; then
local swap_size=$(($swap_max_size / 3))
elif [ $usable_space -ge $(($swap_max_size / 4)) ]; then
local swap_size=$(($swap_max_size / 4))
else
echo "Not enough space left for a swap file" >&2
local swap_size=0
fi
# If there's enough space for a swap, and no existing swap here
if [ $swap_size -ne 0 ] && [ ! -e /swap_$app ]; then
# Create file
truncate -s 0 /swap_$app
# set the No_COW attribute on the swapfile with chattr
chattr +C /swap_$app
# Preallocate space for the swap file, fallocate may sometime not be used, use dd instead in this case
if ! fallocate -l ${swap_size}K /swap_$app; then
dd if=/dev/zero of=/swap_$app bs=1024 count=${swap_size}
fi
chmod 0600 /swap_$app
# Create the swap
mkswap /swap_$app
# And activate it
swapon /swap_$app
# Then add an entry in fstab to load this swap at each boot.
echo -e "/swap_$app swap swap defaults 0 0 #Swap added by $app" >> /etc/fstab
fi
}
ynh_del_swap() {
# If there a swap at this place
if [ -e /swap_$app ]; then
# Clean the fstab
sed -i "/#Swap added by $app/d" /etc/fstab
# Desactive the swap file
swapoff /swap_$app
# And remove it
rm /swap_$app
fi
}
# Check if the device of the main mountpoint "/" is an SD card
#
# [internal]
#
# return 0 if it's an SD card, else 1
ynh_is_main_device_a_sd_card() {
if [ "$(systemd-detect-virt)" != "none" ]; then
# Assume virtualization does not take place on SD card
return 1
fi
local main_device=$(lsblk --output PKNAME --noheadings $(findmnt / --nofsroot --uniq --output source --noheadings --first-only))
if echo $main_device | grep --quiet "mmc" && [ $(tail -n1 /sys/block/$main_device/queue/rotational) == "0" ]; then
return 0
else
return 1
fi
}
# Check available space before creating a temp directory.
#
# usage: ynh_smart_mktemp --min_size="Min size"
#
# | arg: -s, --min_size= - Minimal size needed for the temporary directory, in Mb
ynh_smart_mktemp() {
# Declare an array to define the options of this helper.
declare -Ar args_array=([s]=min_size=)
local min_size
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
min_size="${min_size:-300}"
# Transform the minimum size from megabytes to kilobytes
min_size=$(($min_size * 1024))
# Check if there's enough free space in a directory
is_there_enough_space() {
local free_space=$(df --output=avail "$1" | sed 1d)
test $free_space -ge $min_size
}
if is_there_enough_space /tmp; then
local tmpdir=/tmp
elif is_there_enough_space /var; then
local tmpdir=/var
elif is_there_enough_space /; then
local tmpdir=/
elif is_there_enough_space /home; then
local tmpdir=/home
else
ynh_die "Insufficient free space to continue..."
fi
echo "$(mktemp --directory --tmpdir="$tmpdir")"
}

13
hooks/backup/27-data_xmpp Normal file
View file

@ -0,0 +1,13 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/data/xmpp"
ynh_backup /var/lib/metronome "${backup_dir}/var_lib_metronome"
ynh_backup /var/xmpp-upload/ "${backup_dir}/var_xmpp-upload"

View file

@ -2,167 +2,15 @@
set -e
base_folder_and_perm_init() {
#############################
# Base yunohost conf folder #
#############################
mkdir -p /etc/yunohost
# NB: x permission for 'others' is important for ssl-cert (and maybe mdns), otherwise slapd will fail to start because can't access the certs
chmod 755 /etc/yunohost
################
# Logs folders #
################
mkdir -p /var/log/yunohost
chown root:root /var/log/yunohost
chmod 750 /var/log/yunohost
##################
# Portal folders #
##################
getent passwd ynh-portal &>/dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group ynh-portal
mkdir -p /etc/yunohost/portal
chmod 500 /etc/yunohost/portal
chown ynh-portal:ynh-portal /etc/yunohost/portal
mkdir -p /usr/share/yunohost/portal/customassets
chmod 775 /usr/share/yunohost/portal/customassets
chown root:root /usr/share/yunohost/portal/customassets
touch /var/log/yunohost-portalapi.log
chown ynh-portal:root /var/log/yunohost-portalapi.log
chmod 600 /var/log/yunohost-portalapi.log
###############################
# Sessions folder and secrets #
###############################
# Portal
mkdir -p /var/cache/yunohost-portal/sessions
chown ynh-portal:www-data /var/cache/yunohost-portal
chmod 510 /var/cache/yunohost-portal
chown ynh-portal:www-data /var/cache/yunohost-portal/sessions
chmod 710 /var/cache/yunohost-portal/sessions
# Webadmin
mkdir -p /var/cache/yunohost/sessions
chown root:root /var/cache/yunohost/sessions
chmod 700 /var/cache/yunohost/sessions
if test -e /etc/yunohost/installed
then
# Initialize session secrets
# Obviously we only do this in the post_regen, ie during the postinstall, because we don't want every pre-installed instance to have the same secret
if [ ! -e /etc/yunohost/.admin_cookie_secret ]; then
dd if=/dev/urandom bs=1 count=1000 2>/dev/null | tr --complement --delete 'A-Za-z0-9' | head -c 64 > /etc/yunohost/.admin_cookie_secret
fi
chown root:root /etc/yunohost/.admin_cookie_secret
chmod 400 /etc/yunohost/.admin_cookie_secret
if [ ! -e /etc/yunohost/.ssowat_cookie_secret ]; then
# NB: we need this to be exactly 32 char long, because it is later used as a key for AES256
dd if=/dev/urandom bs=1 count=1000 2>/dev/null | tr --complement --delete 'A-Za-z0-9' | head -c 32 > /etc/yunohost/.ssowat_cookie_secret
fi
chown ynh-portal:root /etc/yunohost/.ssowat_cookie_secret
chmod 400 /etc/yunohost/.ssowat_cookie_secret
fi
##################
# Domain folders #
##################
mkdir -p /etc/yunohost/domains
chown root /etc/yunohost/domains
chmod 700 /etc/yunohost/domains
###############
# App folders #
###############
mkdir -p /etc/yunohost/apps
chown root /etc/yunohost/apps
chmod 700 /etc/yunohost/apps
#####################
# Apps data folders #
#####################
mkdir -p /home/yunohost.app
chmod 755 /home/yunohost.app
################
# Certs folder #
################
mkdir -p /etc/yunohost/certs
chown -R root:ssl-cert /etc/yunohost/certs
chmod 750 /etc/yunohost/certs
# We do this with find because there could be a lot of them...
find /etc/yunohost/certs/ -type f -exec chmod 640 {} \;
find /etc/yunohost/certs/ -type d -exec chmod 750 {} \;
##################
# Backup folders #
##################
mkdir -p /home/yunohost.backup/archives
chmod 770 /home/yunohost.backup
chmod 770 /home/yunohost.backup/archives
if test -e /etc/yunohost/installed
then
# The admins group only exist after the postinstall
chown root:admins /home/yunohost.backup
chown root:admins /home/yunohost.backup/archives
else
chown root:root /home/yunohost.backup
chown root:root /home/yunohost.backup/archives
fi
########
# Misc #
########
mkdir -p /etc/yunohost/hooks.d
chown root /etc/yunohost/hooks.d
chmod 700 /etc/yunohost/hooks.d
mkdir -p /var/cache/yunohost/repo
chown root:root /var/cache/yunohost
chmod 700 /var/cache/yunohost
[ ! -e /var/www/.well-known/ynh-diagnosis/ ] || chmod 775 /var/www/.well-known/ynh-diagnosis/
if test -e /etc/yunohost/installed
then
setfacl -m g:all_users:--- /var/www
setfacl -m g:all_users:--- /var/log/nginx
setfacl -m g:all_users:--- /etc/yunohost
setfacl -m g:all_users:--- /etc/ssowat
fi
}
do_init_regen() {
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2
exit 1
fi
cd /usr/share/yunohost/conf/yunohost
base_folder_and_perm_init
# Empty ssowat json persistent conf
echo "{}" >'/etc/ssowat/conf.json.persistent'
chmod 644 /etc/ssowat/conf.json.persistent
chown root:root /etc/ssowat/conf.json.persistent
echo "{}" >'/etc/ssowat/conf.json'
chmod 644 /etc/ssowat/conf.json
chown root:root /etc/ssowat/conf.json
# Empty service conf
touch /etc/yunohost/services.yml
[[ -d /etc/yunohost ]] || mkdir -p /etc/yunohost
# set default current_host
[[ -f /etc/yunohost/current_host ]] \
@ -176,9 +24,39 @@ do_init_regen() {
[[ -d /etc/skel/media ]] \
|| (mkdir -p /media && ln -s /media /etc/skel/media)
# YunoHost services
# Cert folders
mkdir -p /etc/yunohost/certs
chown -R root:ssl-cert /etc/yunohost/certs
chmod 750 /etc/yunohost/certs
# App folders
mkdir -p /etc/yunohost/apps
chmod 700 /etc/yunohost/apps
mkdir -p /home/yunohost.app
chmod 755 /home/yunohost.app
# Domain settings
mkdir -p /etc/yunohost/domains
chmod 700 /etc/yunohost/domains
# Backup folders
mkdir -p /home/yunohost.backup/archives
chmod 750 /home/yunohost.backup/archives
chown root:root /home/yunohost.backup/archives # This is later changed to root:admins once the admins group exists
# Empty ssowat json persistent conf
echo "{}" > '/etc/ssowat/conf.json.persistent'
chmod 644 /etc/ssowat/conf.json.persistent
chown root:root /etc/ssowat/conf.json.persistent
# Empty service conf
touch /etc/yunohost/services.yml
mkdir -p /var/cache/yunohost/repo
chown root:root /var/cache/yunohost
chmod 700 /var/cache/yunohost
cp yunohost-api.service /etc/systemd/system/yunohost-api.service
cp yunohost-portal-api.service /etc/systemd/system/yunohost-portal-api.service
cp yunohost-firewall.service /etc/systemd/system/yunohost-firewall.service
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
@ -187,9 +65,6 @@ do_init_regen() {
systemctl enable yunohost-api.service --quiet
systemctl start yunohost-api.service
systemctl enable yunohost-portal-api.service --quiet
systemctl start yunohost-portal-api.service
# Enable yunoprompt (in particular for installs from ISO where we want this to show on first boot instead of asking for a login/password)
systemctl enable yunoprompt --quiet
@ -199,8 +74,7 @@ do_init_regen() {
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
if readlink -f /etc/dpkg/origins/default | grep -q debian;
then
if readlink -f /etc/dpkg/origins/default | grep -q debian; then
rm -f /etc/dpkg/origins/default
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
fi
@ -254,8 +128,7 @@ EOF
fi
# Skip ntp if inside a container (inspired from the conf of systemd-timesyncd)
if systemctl | grep -q 'ntp.service'
then
if systemctl | grep -q 'ntp.service'; then
mkdir -p ${pending_dir}/etc/systemd/system/ntp.service.d/
cat > ${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf << EOF
[Unit]
@ -284,7 +157,6 @@ HandleLidSwitchExternalPower=ignore
EOF
cp yunohost-api.service ${pending_dir}/etc/systemd/system/yunohost-api.service
cp yunohost-portal-api.service ${pending_dir}/etc/systemd/system/yunohost-portal-api.service
cp yunohost-firewall.service ${pending_dir}/etc/systemd/system/yunohost-firewall.service
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
@ -299,59 +171,73 @@ EOF
do_post_regen() {
regen_conf_files=$1
# Re-mkdir / apply permission to all basic folders etc
base_folder_and_perm_init
######################
# Enfore permissions #
######################
# Legacy log tree structure
if [ ! -e /var/log/yunohost/operations ]
then
mkdir -p /var/log/yunohost/operations
fi
if [ -d /var/log/yunohost/categories/operation ] && [ ! -L /var/log/yunohost/categories/operation ]
then
# (we use find -type f instead of mv /folder/* to make sure to also move hidden files which are not included in globs by default)
find /var/log/yunohost/categories/operation/ -type f -print0 | xargs -0 -I {} mv {} /var/log/yunohost/operations/
# Attempt to delete the old dir (because we want it to be a symlink) or just rename it if it can't be removed (not empty) for some reason
rmdir /var/log/yunohost/categories/operation || mv /var/log/yunohost/categories/operation /var/log/yunohost/categories/operation.old
ln -s /var/log/yunohost/operations /var/log/yunohost/categories/operation
fi
chmod 770 /home/yunohost.backup
chmod 770 /home/yunohost.backup/archives
chmod 700 /var/cache/yunohost
chown root:admins /home/yunohost.backup
chown root:admins /home/yunohost.backup/archives
chown root:root /var/cache/yunohost
[ ! -e /var/www/.well-known/ynh-diagnosis/ ] || chmod 775 /var/www/.well-known/ynh-diagnosis/
# NB: x permission for 'others' is important for ssl-cert (and maybe mdns), otherwise slapd will fail to start because can't access the certs
chmod 755 /etc/yunohost
# Make sure conf files why may be created by apps are owned and writable only by root
find /etc/systemd/system/*.service -type f | xargs -r chown root:root
find /etc/systemd/system/*.service -type f | xargs -r chmod 0644
if ls -l /etc/php/*/fpm/pool.d/*.conf 2>/dev/null
then
if ls -l /etc/php/*/fpm/pool.d/*.conf; then
chown root:root /etc/php/*/fpm/pool.d/*.conf
chmod 644 /etc/php/*/fpm/pool.d/*.conf
fi
# Certs
# We do this with find because there could be a lot of them...
chown -R root:ssl-cert /etc/yunohost/certs
chmod 750 /etc/yunohost/certs
find /etc/yunohost/certs/ -type f -exec chmod 640 {} \;
find /etc/yunohost/certs/ -type d -exec chmod 750 {} \;
find /etc/cron.*/yunohost-* -type f -exec chmod 755 {} \;
find /etc/cron.d/yunohost-* -type f -exec chmod 644 {} \;
find /etc/cron.*/yunohost-* -type f -exec chown root:root {} \;
setfacl -m g:all_users:--- /var/www
setfacl -m g:all_users:--- /var/log/nginx
setfacl -m g:all_users:--- /etc/yunohost
setfacl -m g:all_users:--- /etc/ssowat
for USER in $(yunohost user list --quiet --output-as json | jq -r '.users | .[] | .username'); do
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
done
# Domain settings
mkdir -p /etc/yunohost/domains
# Misc configuration / state files
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2> /dev/null | grep -vw mdns.yml)
chmod 600 $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2> /dev/null)
# Apps folder, custom hooks folder
[[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d)
[[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps)
[[ ! -e /etc/yunohost/domains ]] || (chown root /etc/yunohost/domains && chmod 700 /etc/yunohost/domains)
# Create ssh.app and sftp.app groups if they don't exist yet
grep -q '^ssh.app:' /etc/group || groupadd ssh.app
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
# Propagates changes in systemd service config overrides
if systemctl | grep -q 'ntp.service'
then
if systemctl | grep -q 'ntp.service'; then
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
systemctl daemon-reload
systemctl restart ntp
}
fi
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || {
systemctl daemon-reload
@ -359,7 +245,6 @@ do_post_regen() {
}
[[ ! "$regen_conf_files" =~ "yunohost-firewall.service" ]] || systemctl daemon-reload
[[ ! "$regen_conf_files" =~ "yunohost-api.service" ]] || systemctl daemon-reload
[[ ! "$regen_conf_files" =~ "yunohost-portal-api.service" ]] || systemctl daemon-reload
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
systemctl daemon-reload
@ -372,19 +257,14 @@ do_post_regen() {
systemctl $action proc-hidepid --quiet --now
fi
systemctl enable yunohost-portal-api.service --quiet
systemctl is-active yunohost-portal-api --quiet || systemctl start yunohost-portal-api.service
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
if readlink -f /etc/dpkg/origins/default | grep -q debian;
then
if readlink -f /etc/dpkg/origins/default | grep -q debian; then
rm -f /etc/dpkg/origins/default
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
fi
if test -e /etc/yunohost/installed && test -e /etc/profile.d/check_yunohost_is_installed.sh
then
if test -e /etc/yunohost/installed && test -e /etc/profile.d/check_yunohost_is_installed.sh; then
rm /etc/profile.d/check_yunohost_is_installed.sh
fi
}

View file

@ -106,8 +106,7 @@ do_post_regen() {
main_domain=$(cat /etc/yunohost/current_host)
# Automigrate legacy folder
if [ -e /usr/share/yunohost/yunohost-config/ssl/yunoCA ]
then
if [ -e /usr/share/yunohost/yunohost-config/ssl/yunoCA ]; then
mv /usr/share/yunohost/yunohost-config/ssl/yunoCA/* ${ssl_dir}
rm -rf /usr/share/yunohost/yunohost-config
# Overwrite openssl.cnf because it may still contain references to the old yunoCA dir

View file

@ -9,16 +9,17 @@ do_pre_regen() {
cd /usr/share/yunohost/conf/ssh
# Support different strategy for security configurations
export compatibility="$(jq -r '.ssh_compatibility' <<< "$YNH_SETTINGS")"
export port="$(jq -r '.ssh_port' <<< "$YNH_SETTINGS")"
export password_authentication="$(jq -r '.ssh_password_authentication' <<< "$YNH_SETTINGS" | int_to_bool)"
export ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null || true)
# do not listen to IPv6 if unavailable
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
export ipv6_enabled
ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2> /dev/null || true)
# Support different strategy for security configurations
export compatibility="$(yunohost settings get 'security.ssh.ssh_compatibility')"
export port="$(yunohost settings get 'security.ssh.ssh_port')"
export password_authentication="$(yunohost settings get 'security.ssh.ssh_password_authentication' | int_to_bool)"
export ssh_keys
export ipv6_enabled
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}

View file

@ -8,6 +8,10 @@ config="/usr/share/yunohost/conf/slapd/config.ldif"
db_init="/usr/share/yunohost/conf/slapd/db_init.ldif"
do_init_regen() {
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2
exit 1
fi
do_pre_regen ""

View file

@ -11,7 +11,7 @@ do_pre_regen() {
# Add sury
mkdir -p ${pending_dir}/etc/apt/sources.list.d/
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"
echo "deb 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
echo "
@ -27,20 +27,6 @@ Pin: origin \"packages.sury.org\"
Pin-Priority: -1" >> "${pending_dir}/etc/apt/preferences.d/extra_php_version"
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 "
# PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
@ -70,7 +56,6 @@ Pin: release *
Pin-Priority: -1
" >> "${pending_dir}/etc/apt/preferences.d/ban_packages"
}
do_post_regen() {
@ -82,20 +67,12 @@ do_post_regen() {
# Add sury key
# We do this only at the post regen and if the key doesn't already exists, because we don't want the regenconf to fuck everything up if the regenconf runs while the network is down
if [[ ! -s /etc/apt/trusted.gpg.d/extra_php_version.gpg ]]
then
if [[ ! -s /etc/apt/trusted.gpg.d/extra_php_version.gpg ]]; then
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
# 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
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION
then
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION; then
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
fi
}

91
hooks/conf_regen/12-metronome Executable file
View file

@ -0,0 +1,91 @@
#!/bin/bash
set -e
if ! dpkg --list | grep -q 'ii *metronome '; then
echo 'metronome is not installed, skipping'
exit 0
fi
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/conf/metronome
# create directories for pending conf
metronome_dir="${pending_dir}/etc/metronome"
metronome_conf_dir="${metronome_dir}/conf.d"
mkdir -p "$metronome_conf_dir"
# retrieve variables
main_domain=$(cat /etc/yunohost/current_host)
# install main conf file
cat metronome.cfg.lua \
| sed "s/{{ main_domain }}/${main_domain}/g" \
> "${metronome_dir}/metronome.cfg.lua"
# Trick such that old conf files are flagged as to remove
for domain in $YNH_DOMAINS; do
touch "${metronome_conf_dir}/${domain}.cfg.lua"
done
# add domain conf files
domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")"
for domain in $domain_list; do
cat domain.tpl.cfg.lua \
| sed "s/{{ domain }}/${domain}/g" \
> "${metronome_conf_dir}/${domain}.cfg.lua"
done
# remove old domain conf files
conf_files=$(ls -1 /etc/metronome/conf.d \
| awk '/^[^\.]+\.[^\.]+.*\.cfg\.lua$/ { print $1 }')
for file in $conf_files; do
domain=${file%.cfg.lua}
[[ $YNH_DOMAINS =~ $domain ]] \
|| touch "${metronome_conf_dir}/${file}"
done
}
do_post_regen() {
regen_conf_files=$1
# retrieve variables
main_domain=$(cat /etc/yunohost/current_host)
# create metronome directories for domains
for domain in $YNH_MAIN_DOMAINS; do
mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
# http_upload directory must be writable by metronome and readable by nginx
mkdir -p "/var/xmpp-upload/${domain}/upload"
# sgid bit allows that file created in that dir will be owned by www-data
# despite the fact that metronome ain't in the www-data group
chmod g+s "/var/xmpp-upload/${domain}/upload"
done
# fix some permissions
[ ! -e '/var/xmpp-upload' ] || chown -R metronome:www-data "/var/xmpp-upload/"
[ ! -e '/var/xmpp-upload' ] || chmod 750 "/var/xmpp-upload/"
# metronome should be in ssl-cert group to let it access SSL certificates
usermod -aG ssl-cert metronome
chown -R metronome: /var/lib/metronome/
chown -R metronome: /etc/metronome/conf.d/
if [[ -z "$(ls /etc/metronome/conf.d/*.cfg.lua 2> /dev/null)" ]]; then
if systemctl is-enabled metronome &> /dev/null; then
systemctl disable metronome --now 2> /dev/null
fi
else
if ! systemctl is-enabled metronome &> /dev/null; then
systemctl enable metronome --now 2> /dev/null
sleep 3
fi
[[ -z "$regen_conf_files" ]] \
|| systemctl restart metronome
fi
}
do_$1_regen ${@:2}

View file

@ -4,20 +4,25 @@ set -e
. /usr/share/yunohost/helpers
do_base_regen() {
do_init_regen() {
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2
exit 1
fi
pending_dir=$1
nginx_dir="${pending_dir}/etc/nginx"
cd /usr/share/yunohost/conf/nginx
nginx_dir="/etc/nginx"
nginx_conf_dir="${nginx_dir}/conf.d"
mkdir -p "$nginx_conf_dir"
# install plain conf files
cp acme-challenge.conf.inc "$nginx_conf_dir"
cp global.conf "$nginx_conf_dir"
cp ssowat.conf "$nginx_conf_dir"
cp yunohost_http_errors.conf.inc "$nginx_conf_dir"
cp yunohost_sso.conf.inc "$nginx_conf_dir"
cp plain/* "$nginx_conf_dir"
# probably run with init: just disable default site, restart NGINX and exit
rm -f "${nginx_dir}/sites-enabled/default"
export compatibility="intermediate"
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
@ -25,17 +30,6 @@ do_base_regen() {
mkdir -p $nginx_conf_dir/default.d/
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
}
do_init_regen() {
cd /usr/share/yunohost/conf/nginx
export compatibility="intermediate"
do_base_regen ""
# probably run with init: just disable default site, restart NGINX and exit
rm -f "${nginx_dir}/sites-enabled/default"
# Restart nginx if conf looks good, otherwise display error and exit unhappy
nginx -t 2> /dev/null || {
@ -59,21 +53,27 @@ do_pre_regen() {
nginx_conf_dir="${nginx_dir}/conf.d"
mkdir -p "$nginx_conf_dir"
export webadmin_allowlist_enabled="$(jq -r '.webadmin_allowlist_enabled' <<< "$YNH_SETTINGS" | int_to_bool)"
if [ "$webadmin_allowlist_enabled" == "True" ]; then
export webadmin_allowlist="$(jq -r '.webadmin_allowlist' <<< "$YNH_SETTINGS" | sed 's/^null$//g')"
# install / update plain conf files
cp plain/* "$nginx_conf_dir"
# remove the panel overlay if this is specified in settings
panel_overlay=$(yunohost settings get 'misc.portal.ssowat_panel_overlay_enabled' | int_to_bool)
if [ "$panel_overlay" == "False" ]; then
echo "#" > "${nginx_conf_dir}/yunohost_panel.conf.inc"
fi
# Support different strategy for security configurations
export redirect_to_https="$(jq -r '.nginx_redirect_to_https' <<< "$YNH_SETTINGS" | int_to_bool)"
export compatibility="$(jq -r '.nginx_compatibility' <<< "$YNH_SETTINGS" | int_to_bool)"
export experimental="$(jq -r '.security_experimental_enabled' <<< "$YNH_SETTINGS" | int_to_bool)"
# retrieve variables
main_domain=$(cat /etc/yunohost/current_host)
do_base_regen "${pending_dir}"
# Support different strategy for security configurations
export redirect_to_https="$(yunohost settings get 'security.nginx.nginx_redirect_to_https' | int_to_bool)"
export compatibility="$(yunohost settings get 'security.nginx.nginx_compatibility')"
export experimental="$(yunohost settings get 'security.experimental.security_experimental_enabled' | int_to_bool)"
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
cert_status=$(yunohost domain cert status --json)
# add domain conf files
xmpp_domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")"
mail_domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]")"
for domain in $YNH_DOMAINS; do
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
@ -86,16 +86,19 @@ do_pre_regen() {
export domain_cert_ca=$(echo $cert_status \
| jq ".certificates.\"$domain\".CA_type" \
| tr -d '"')
if echo "$mail_domain_list" | grep -q "^$domain$"
then
if echo "$xmpp_domain_list" | grep -q "^$domain$"; then
export xmpp_enabled="True"
else
export xmpp_enabled="False"
fi
if echo "$mail_domain_list" | grep -q "^$domain$"; then
export mail_enabled="True"
else
export mail_enabled="False"
fi
ynh_render_template "server.tpl.conf" "${nginx_conf_dir}/${domain}.conf"
if [ $mail_enabled == "True" ]
then
if [ $mail_enabled == "True" ]; then
ynh_render_template "autoconfig.tpl.xml" "${mail_autoconfig_dir}/config-v1.1.xml"
fi
@ -103,8 +106,15 @@ do_pre_regen() {
done
# Legacy file to remove, but we can't really remove it because it may be included by app confs...
echo "# The old yunohost panel/tile/button doesn't exists anymore" > "$nginx_conf_dir"/yunohost_panel.conf.inc
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.webadmin_allowlist_enabled | int_to_bool)
if [ "$webadmin_allowlist_enabled" == "True" ]; then
export webadmin_allowlist=$(yunohost settings get security.webadmin.webadmin_allowlist)
fi
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
ynh_render_template "yunohost_api.conf.inc" "${nginx_conf_dir}/yunohost_api.conf.inc"
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
mkdir -p $nginx_conf_dir/default.d/
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
# remove old domain conf files
conf_files=$(ls -1 /etc/nginx/conf.d \
@ -131,8 +141,7 @@ do_pre_regen() {
do_post_regen() {
regen_conf_files=$1
if ls -l /etc/nginx/conf.d/*.d/*.conf
then
if ls -l /etc/nginx/conf.d/*.d/*.conf; then
chown root:root /etc/nginx/conf.d/*.d/*.conf
chmod 644 /etc/nginx/conf.d/*.d/*.conf
fi

View file

@ -22,19 +22,19 @@ do_pre_regen() {
main_domain=$(cat /etc/yunohost/current_host)
# Support different strategy for security configurations
export compatibility="$(jq -r '.postfix_compatibility' <<< "$YNH_SETTINGS")"
export compatibility="$(yunohost settings get 'security.postfix.postfix_compatibility')"
# Add possibility to specify a relay
# Could be useful with some isp with no 25 port open or more complex setup
export relay_port=""
export relay_user=""
export relay_host=""
export relay_enabled="$(jq -r '.smtp_relay_enabled' <<< "$YNH_SETTINGS" | int_to_bool)"
export relay_enabled="$(yunohost settings get 'email.smtp.smtp_relay_enabled' | int_to_bool)"
if [ "${relay_enabled}" == "True" ]; then
relay_host="$(jq -r '.smtp_relay_host' <<< "$YNH_SETTINGS")"
relay_port="$(jq -r '.smtp_relay_port' <<< "$YNH_SETTINGS")"
relay_user="$(jq -r '.smtp_relay_user' <<< "$YNH_SETTINGS")"
relay_password="$(jq -r '.smtp_relay_password' <<< "$YNH_SETTINGS")"
relay_host="$(yunohost settings get 'email.smtp.smtp_relay_host')"
relay_port="$(yunohost settings get 'email.smtp.smtp_relay_port')"
relay_user="$(yunohost settings get 'email.smtp.smtp_relay_user')"
relay_password="$(yunohost settings get 'email.smtp.smtp_relay_password')"
# Avoid to display "Relay account paswword" to other users
touch ${postfix_dir}/sasl_passwd
@ -45,6 +45,19 @@ do_pre_regen() {
cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd
fi
# Use this postfix server as a backup MX
export backup_mx_domains="$(yunohost settings get 'email.smtp.smtp_backup_mx_domains' | sed "s/,/ /g")"
export backup_mx_emails="$(yunohost settings get 'email.smtp.smtp_backup_mx_emails_whitelisted' | sed "s/,/ /g")"
rm -f ${postfix_dir}/relay_recipients
touch ${postfix_dir}/relay_recipients
if [ -n "${backup_mx_domains}" ] && [ -n "${backup_mx_emails}" ]; then
for mail in ${backup_mx_emails}; do
echo "$mail OK" >> ${postfix_dir}/relay_recipients
done
postmap ${postfix_dir}/relay_recipients
fi
export main_domain
export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
ynh_render_template "main.cf" "${postfix_dir}/main.cf"
@ -56,7 +69,7 @@ do_pre_regen() {
> "${default_dir}/postsrsd"
# adapt it for IPv4-only hosts
ipv6="$(jq -r '.smtp_allow_ipv6' <<< "$YNH_SETTINGS" | int_to_bool)"
ipv6="$(yunohost settings get 'email.smtp.smtp_allow_ipv6' | int_to_bool)"
if [ "$ipv6" == "False" ] || [ ! -f /proc/net/if_inet6 ]; then
sed -i \
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
@ -78,6 +91,11 @@ do_post_regen() {
postmap /etc/postfix/sasl_passwd
fi
if [ -e /etc/postfix/relay_recipients ]; then
chmod 750 /etc/postfix/relay_recipients*
chown postfix:root /etc/postfix/relay_recipients*
fi
postmap -F hash:/etc/postfix/sni
python3 -c 'from yunohost.app import regen_mail_app_user_config_for_dovecot_and_postfix as r; r(only="postfix")'

View file

@ -16,7 +16,7 @@ do_pre_regen() {
cp dovecot-ldap.conf "${dovecot_dir}/dovecot-ldap.conf"
cp dovecot.sieve "${dovecot_dir}/global_script/dovecot.sieve"
export pop3_enabled="$(jq -r '.pop3_enabled' <<< "$YNH_SETTINGS" | int_to_bool)"
export pop3_enabled="$(yunohost settings get 'email.pop3.pop3_enabled' | int_to_bool)"
export main_domain=$(cat /etc/yunohost/current_host)
export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
@ -42,7 +42,7 @@ do_post_regen() {
# create vmail user
id vmail > /dev/null 2>&1 \
|| { mkdir -p /var/vmail; adduser --system --ingroup mail --uid 500 vmail --home /var/vmail --no-create-home; }
|| adduser --system --ingroup mail --uid 500 vmail --home /var/vmail --no-create-home
# Delete legacy home for vmail that existed in the past but was empty, poluting /home/
[ ! -e /home/vmail ] || rmdir --ignore-fail-on-non-empty /home/vmail

View file

@ -1,43 +0,0 @@
#!/bin/bash
set -e
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/conf/opendkim
install -D -m 644 opendkim.conf "${pending_dir}/etc/opendkim.conf"
}
do_post_regen() {
mkdir -p /etc/dkim
# Create / empty those files because we're force-regenerating them
echo "" > /etc/dkim/keytable
echo "" > /etc/dkim/signingtable
# create DKIM key for domains
domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
for domain in $domain_list; do
domain_key="/etc/dkim/${domain}.mail.key"
[ ! -f "$domain_key" ] && {
# We use a 1024 bit size because nsupdate doesn't seem to be able to
# handle 2048...
opendkim-genkey --domain="$domain" \
--selector=mail --directory=/etc/dkim -b 1024
mv /etc/dkim/mail.private "$domain_key"
mv /etc/dkim/mail.txt "/etc/dkim/${domain}.mail.txt"
}
echo "mail._domainkey.${domain} ${domain}:mail:${domain_key}" >> /etc/dkim/keytable
echo "*@$domain mail._domainkey.${domain}" >> /etc/dkim/signingtable
done
chown -R opendkim /etc/dkim/
chmod 700 /etc/dkim/
systemctl restart opendkim
}
do_$1_regen ${@:2}

65
hooks/conf_regen/31-rspamd Executable file
View file

@ -0,0 +1,65 @@
#!/bin/bash
set -e
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/conf/rspamd
install -D -m 644 metrics.local.conf \
"${pending_dir}/etc/rspamd/local.d/metrics.conf"
install -D -m 644 dkim_signing.conf \
"${pending_dir}/etc/rspamd/local.d/dkim_signing.conf"
install -D -m 644 rspamd.sieve \
"${pending_dir}/etc/dovecot/global_script/rspamd.sieve"
install -D -m 644 redis.conf \
"${pending_dir}/etc/rspamd/local.d/redis.conf"
}
do_post_regen() {
##
## DKIM key generation
##
# create DKIM directory with proper permission
mkdir -p /etc/dkim
chown _rspamd /etc/dkim
# create DKIM key for domains
domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
for domain in $domain_list; do
domain_key="/etc/dkim/${domain}.mail.key"
[ ! -f "$domain_key" ] && {
# We use a 1024 bit size because nsupdate doesn't seem to be able to
# handle 2048...
opendkim-genkey --domain="$domain" \
--selector=mail --directory=/etc/dkim -b 1024
mv /etc/dkim/mail.private "$domain_key"
mv /etc/dkim/mail.txt "/etc/dkim/${domain}.mail.txt"
}
done
# fix DKIM keys permissions
chown _rspamd /etc/dkim/*.mail.key
chmod 400 /etc/dkim/*.mail.key
[ ! -e /var/log/rspamd ] || chown -R _rspamd:_rspamd /var/log/rspamd
regen_conf_files=$1
[ -z "$regen_conf_files" ] && exit 0
# compile sieve script
[[ "$regen_conf_files" =~ rspamd\.sieve ]] && {
sievec /etc/dovecot/global_script/rspamd.sieve
chown -R vmail:mail /etc/dovecot/global_script
systemctl restart dovecot
}
# Restart rspamd due to the upgrade
# https://rspamd.com/announce/2016/08/01/rspamd-1.3.1.html
systemctl -q restart rspamd.service
}
do_$1_regen ${@:2}

Some files were not shown because too many files have changed in this diff Show more