mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge remote-tracking branch 'origin/bookworm' into new-log-streaming-api
This commit is contained in:
commit
23b24cf9f2
263 changed files with 20242 additions and 9711 deletions
30
.github/workflows/autoblack.yml
vendored
Normal file
30
.github/workflows/autoblack.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
name: Check / auto apply Black
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev" ]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
name: Check / auto apply black
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check files using the black formatter
|
||||
uses: psf/black@stable
|
||||
id: black
|
||||
with:
|
||||
options: "."
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
title: "Format Python code with Black"
|
||||
commit-message: ":art: Format Python code with Black"
|
||||
body: |
|
||||
This pull request uses the [psf/black](https://github.com/psf/black) formatter.
|
||||
base: ${{ github.head_ref }} # Creates pull request onto pull request or commit branch
|
||||
branch: actions/black
|
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
|
30
.github/workflows/n_updater.yml
vendored
30
.github/workflows/n_updater.yml
vendored
|
@ -11,37 +11,29 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch the source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run the updater script
|
||||
id: run_updater
|
||||
run: |
|
||||
# Setting up Git user
|
||||
git config --global user.name 'yunohost-bot'
|
||||
git config --global user.email 'yunohost-bot@users.noreply.github.com'
|
||||
# Run the updater script
|
||||
# Download n
|
||||
wget https://raw.githubusercontent.com/tj/n/master/bin/n --output-document=helpers/vendor/n/n
|
||||
[[ -z "$(git diff helpers/vendor/n/n)" ]] || echo "PROCEED=true" >> $GITHUB_ENV
|
||||
- name: Commit changes
|
||||
id: commit
|
||||
if: ${{ env.PROCEED == 'true' }}
|
||||
run: |
|
||||
git commit -am "Upgrade n to v$VERSION"
|
||||
|
||||
echo "VERSION=$(sed -n 's/^VERSION=\"\(.*\)\"/\1/p' < helpers/vendor/n/n)" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
id: cpr
|
||||
if: ${{ env.PROCEED == 'true' }}
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update n to version ${{ env.VERSION }}
|
||||
commit-message: Update n to ${{ env.VERSION }}
|
||||
committer: 'yunohost-bot <yunohost-bot@users.noreply.github.com>'
|
||||
author: 'yunohost-bot <yunohost-bot@users.noreply.github.com>'
|
||||
signoff: false
|
||||
base: dev
|
||||
branch: ci-auto-update-n-v${{ env.VERSION }}
|
||||
branch: ci-auto-update-n-${{ env.VERSION }}
|
||||
delete-branch: true
|
||||
title: 'Upgrade n to version ${{ env.VERSION }}'
|
||||
title: 'Upgrade n to ${{ env.VERSION }}'
|
||||
body: |
|
||||
Upgrade `n` to v${{ env.VERSION }}
|
||||
Upgrade `n` to ${{ env.VERSION }}
|
||||
draft: false
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
---
|
||||
stages:
|
||||
- lint
|
||||
- build
|
||||
- install
|
||||
- test
|
||||
- lint
|
||||
- doc
|
||||
- translation
|
||||
- bot
|
||||
|
||||
default:
|
||||
tags:
|
||||
|
|
53
.gitlab/ci/bot.gitlab-ci.yml
Normal file
53
.gitlab/ci/bot.gitlab-ci.yml
Normal file
|
@ -0,0 +1,53 @@
|
|||
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/*
|
|
@ -1,5 +1,8 @@
|
|||
.build-stage:
|
||||
stage: build
|
||||
needs:
|
||||
- job: actionsmap
|
||||
- job: invalidcode311
|
||||
image: "before-install"
|
||||
variables:
|
||||
YNH_SOURCE: "https://github.com/yunohost"
|
||||
|
@ -13,6 +16,8 @@
|
|||
.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."
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
########################################
|
||||
# DOC
|
||||
########################################
|
||||
|
||||
generate-helpers-doc:
|
||||
stage: doc
|
||||
image: "before-install"
|
||||
needs: []
|
||||
before_script:
|
||||
- apt-get update -y && apt-get install git hub -y
|
||||
- git config --global user.email "yunohost@yunohost.org"
|
||||
- git config --global user.name "$GITHUB_USER"
|
||||
script:
|
||||
- cd doc
|
||||
- python3 generate_helper_doc.py
|
||||
- python3 generate_resource_doc.py > resources.md
|
||||
- hub clone https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/doc.git doc_repo
|
||||
- cp helpers.md doc_repo/pages/06.contribute/10.packaging_apps/80.resources/11.helpers/packaging_apps_helpers.md
|
||||
- cp resources.md doc_repo/pages/06.contribute/10.packaging_apps/80.resources/15.appresources/packaging_apps_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
|
|
@ -17,7 +17,9 @@ upgrade:
|
|||
image: "after-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
|
||||
|
||||
|
||||
install-postinstall:
|
||||
|
@ -25,5 +27,7 @@ install-postinstall:
|
|||
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
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
########################################
|
||||
# later we must fix lint and format-check jobs and remove "allow_failure"
|
||||
|
||||
actionsmap:
|
||||
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"
|
||||
|
@ -25,23 +33,8 @@ mypy:
|
|||
script:
|
||||
- tox -e py311-mypy
|
||||
|
||||
black:
|
||||
i18n-keys:
|
||||
stage: lint
|
||||
image: "before-install"
|
||||
needs: []
|
||||
before_script:
|
||||
- apt-get update -y && apt-get install git hub -y
|
||||
- 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-format-${CI_COMMIT_REF_NAME}" --no-track
|
||||
- tox -e py311-black-run
|
||||
- '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
|
||||
- git commit -am "[CI] Format code with Black" || true
|
||||
- git push -f origin "ci-format-${CI_COMMIT_REF_NAME}":"ci-format-${CI_COMMIT_REF_NAME}"
|
||||
- hub pull-request -m "[CI] Format code with Black" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
|
||||
only:
|
||||
- tags
|
||||
- python3 maintenance/missing_i18n_keys.py --check
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.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 php8.2-cli mariadb-client mariadb-server
|
||||
- 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
|
||||
|
@ -26,174 +26,172 @@
|
|||
# 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
|
||||
- cd tests
|
||||
- bash test_helpers.sh
|
||||
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
|
||||
# - 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-helpers:
|
||||
test-helpers2:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd tests
|
||||
- bash test_helpers.sh
|
||||
only:
|
||||
changes:
|
||||
- helpers/*
|
||||
|
||||
test-helpers2.1:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- cd tests
|
||||
- bash test_helpers.sh 2.1
|
||||
|
||||
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
|
||||
# only:
|
||||
# changes:
|
||||
# - src/authenticators/*.py
|
||||
|
||||
test-sso-and-portalapi:
|
||||
extends: .test-stage
|
||||
script:
|
||||
- python3 -m pytest src/tests/test_sso_and_portalapi.py
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
########################################
|
||||
# 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: "before-install"
|
||||
needs: []
|
||||
before_script:
|
||||
- apt-get update -y && apt-get install git hub -y
|
||||
- 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/*
|
30
README.md
30
README.md
|
@ -19,31 +19,31 @@ YunoHost is an operating system aiming to simplify as much as possible the admin
|
|||
|
||||
This repository corresponds to the core code of YunoHost, mainly written in Python and Bash.
|
||||
|
||||
- [Project features](https://yunohost.org/#/whatsyunohost)
|
||||
- [Project features](https://yunohost.org/whatsyunohost)
|
||||
- [Project website](https://yunohost.org)
|
||||
- [Install documentation](https://yunohost.org/install)
|
||||
- [Issue tracker](https://github.com/YunoHost/issues)
|
||||
|
||||
# Screenshots
|
||||
## Screenshots
|
||||
|
||||
Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single sign-on user portal ([SSOwat](https://github.com/YunoHost/ssowat))
|
||||
--- | ---
|
||||
 | 
|
||||
 | 
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
- You can learn how to get started with developing on YunoHost by reading [this piece of documentation](https://yunohost.org/dev).
|
||||
- Come chat with us on the [dev chatroom](https://yunohost.org/#/chat_rooms) !
|
||||
- You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget)
|
||||
- Come chat with us on the [dev chatroom](https://yunohost.org/chat_rooms)!
|
||||
- You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget).
|
||||
|
||||
<p align="center">
|
||||
<img src="https://translate.yunohost.org/widgets/yunohost/-/core/horizontal-auto.svg" alt="Translation status" />
|
||||
<img alt="View of the translation rate for the different languages available in YunoHost" src="https://translate.yunohost.org/widgets/yunohost/-/core/horizontal-auto.svg" alt="Translation status" />
|
||||
</p>
|
||||
|
||||
## License
|
||||
|
||||
As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed under GNU AGPL v3.
|
||||
As [other components of YunoHost](https://yunohost.org/faq), this repository is licensed under GNU AGPL v3.
|
||||
|
||||
## They support us <3
|
||||
|
||||
|
@ -51,16 +51,16 @@ We are thankful for our sponsors providing us with infrastructure and grants!
|
|||
|
||||
<div align="center">
|
||||
<p style="margin-left:auto;margin-right:auto;">
|
||||
<a style="padding: 5px;" href="https://nlnet.nl"><img src="https://user-images.githubusercontent.com/36127788/198088570-823c40bd-7ac3-44e3-a8ee-e7a9f14b47ac.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.ngi.eu"><img src="https://user-images.githubusercontent.com/36127788/198088663-daf587b9-fd09-4c00-aaf2-37c803939c94.png" width="130px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.codelutin.com"><img src="https://user-images.githubusercontent.com/36127788/198088737-d37b6674-379c-4be4-9d74-b93b6ad318d1.png" width="100px"/></a>
|
||||
<a style="padding: 5px;" href="https://nlnet.nl"><img alt="NLnet Foundation" src="https://user-images.githubusercontent.com/36127788/198088570-823c40bd-7ac3-44e3-a8ee-e7a9f14b47ac.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.ngi.eu"><img alt="Next Generation Internet" src="https://user-images.githubusercontent.com/36127788/198088663-daf587b9-fd09-4c00-aaf2-37c803939c94.png" width="130px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.codelutin.com"><img alt="Code Lutin" src="https://user-images.githubusercontent.com/36127788/198088737-d37b6674-379c-4be4-9d74-b93b6ad318d1.png" width="100px"/></a>
|
||||
</p>
|
||||
<p style="margin-left:auto;margin-right:auto;">
|
||||
<a style="padding: 5px;" href="https://www.globenet.org"><img src="https://user-images.githubusercontent.com/36127788/198088794-751129ab-737d-4d99-9f35-5e01845dcdfe.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.gitoyen.net"><img src="https://user-images.githubusercontent.com/36127788/198088931-f16f4af4-57ae-42e9-8d42-fb3e2d8d7ee3.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://tetaneutral.net"><img src="https://user-images.githubusercontent.com/36127788/198088995-3ad9c34d-9807-4ead-934b-44df97d3c552.png" width="90px"/></a>
|
||||
<a style="padding: 5px;" href="https://ldn-fai.net"><img src="https://user-images.githubusercontent.com/36127788/198089086-a4089d51-9173-4081-bd2e-fa1ac3378e49.png" width="120px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.nbs-system.com"><img src="https://user-images.githubusercontent.com/36127788/198089161-4cc0b7b7-bf56-4798-892e-a76112497921.png" width="130px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.globenet.org"><img alt="Globenet" src="https://user-images.githubusercontent.com/36127788/198088794-751129ab-737d-4d99-9f35-5e01845dcdfe.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.gitoyen.net"><img alt="Gitoyen" src="https://user-images.githubusercontent.com/36127788/198088931-f16f4af4-57ae-42e9-8d42-fb3e2d8d7ee3.png" width="150px"/></a>
|
||||
<a style="padding: 5px;" href="https://tetaneutral.net"><img alt="tetaneutral.net" src="https://user-images.githubusercontent.com/36127788/198088995-3ad9c34d-9807-4ead-934b-44df97d3c552.png" width="90px"/></a>
|
||||
<a style="padding: 5px;" href="https://ldn-fai.net"><img alt="LDN (Lorraine Data Network)" src="https://user-images.githubusercontent.com/36127788/198089086-a4089d51-9173-4081-bd2e-fa1ac3378e49.png" width="120px"/></a>
|
||||
<a style="padding: 5px;" href="https://www.nbs-system.com"><img alt="NBS System" src="https://user-images.githubusercontent.com/36127788/198089161-4cc0b7b7-bf56-4798-892e-a76112497921.png" width="130px"/></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
53
bin/yunohost-portal-api
Executable file
53
bin/yunohost-portal-api
Executable file
|
@ -0,0 +1,53 @@
|
|||
#! /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)
|
|
@ -1,77 +1,34 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env python3
|
||||
|
||||
set -e
|
||||
set -u
|
||||
import sys
|
||||
import requests
|
||||
import json
|
||||
|
||||
PASTE_URL="https://paste.yunohost.org"
|
||||
SERVER_URL = "https://paste.yunohost.org"
|
||||
TIMEOUT = 3
|
||||
|
||||
_die() {
|
||||
printf "Error: %s\n" "$*"
|
||||
exit 1
|
||||
}
|
||||
def create_snippet(data):
|
||||
try:
|
||||
url = SERVER_URL + "/documents"
|
||||
response = requests.post(url, data=data.encode('utf-8'), timeout=TIMEOUT)
|
||||
response.raise_for_status()
|
||||
dockey = json.loads(response.text)['key']
|
||||
return SERVER_URL + "/raw/" + dockey
|
||||
except requests.exceptions.RequestException as e:
|
||||
print("\033[31mError: {}\033[0m".format(e))
|
||||
sys.exit(1)
|
||||
|
||||
check_dependencies() {
|
||||
curl -V > /dev/null 2>&1 || _die "This script requires curl."
|
||||
}
|
||||
|
||||
paste_data() {
|
||||
json=$(curl -X POST -s -d "$1" "${PASTE_URL}/documents")
|
||||
[[ -z "$json" ]] && _die "Unable to post the data to the server."
|
||||
def main():
|
||||
output = sys.stdin.read()
|
||||
|
||||
key=$(echo "$json" \
|
||||
| python3 -c 'import json,sys;o=json.load(sys.stdin);print(o["key"])' \
|
||||
2>/dev/null)
|
||||
[[ -z "$key" ]] && _die "Unable to parse the server response."
|
||||
if not output:
|
||||
print("\033[31mError: No input received from stdin.\033[0m")
|
||||
sys.exit(1)
|
||||
|
||||
echo "${PASTE_URL}/${key}"
|
||||
}
|
||||
url = create_snippet(output)
|
||||
|
||||
usage() {
|
||||
printf "Usage: ${0} [OPTION]...
|
||||
print("\033[32mURL: {}\033[0m".format(url))
|
||||
|
||||
Read from input stream and paste the data to the YunoHost
|
||||
Haste server.
|
||||
|
||||
For example, to paste the output of the YunoHost diagnosis, you
|
||||
can simply execute the following:
|
||||
yunohost diagnosis show | ${0}
|
||||
|
||||
It will return the URL where you can access the pasted data.
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
"
|
||||
}
|
||||
|
||||
main() {
|
||||
# parse options
|
||||
while (( ${#} )); do
|
||||
case "${1}" in
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown parameter detected: ${1}" >&2
|
||||
echo >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
shift 1
|
||||
done
|
||||
|
||||
# check input stream
|
||||
read -t 0 || {
|
||||
echo -e "Invalid usage: No input is provided.\n" >&2
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
paste_data "$(cat)"
|
||||
}
|
||||
|
||||
check_dependencies
|
||||
|
||||
main "${@}"
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
{% 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
|
||||
|
|
|
@ -13,9 +13,8 @@ protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %}
|
|||
mail_plugins = $mail_plugins quota notify push_notification
|
||||
|
||||
###############################################################################
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
ssl = required
|
||||
|
||||
|
@ -32,20 +31,32 @@ 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
|
||||
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
||||
ssl_prefer_server_ciphers = no
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Regular Yunohost accounts
|
||||
passdb {
|
||||
args = /etc/dovecot/dovecot-ldap.conf
|
||||
driver = ldap
|
||||
}
|
||||
|
||||
# Internally, allow authentication from apps system user who have "enable_email = true"
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = /etc/dovecot/app-senders-passwd
|
||||
}
|
||||
|
||||
userdb {
|
||||
args = /etc/dovecot/dovecot-ldap.conf
|
||||
driver = ldap
|
||||
args = /etc/dovecot/dovecot-ldap.conf
|
||||
}
|
||||
|
||||
userdb {
|
||||
driver = passwd-file
|
||||
args = username_format=%n /etc/dovecot/app-senders-passwd
|
||||
}
|
||||
|
||||
protocol imap {
|
||||
|
@ -53,13 +64,40 @@ protocol imap {
|
|||
mail_plugins = $mail_plugins imap_quota antispam
|
||||
}
|
||||
|
||||
|
||||
protocol lda {
|
||||
auth_socket_path = /var/run/dovecot/auth-master
|
||||
mail_plugins = quota sieve
|
||||
postmaster_address = postmaster@{{ main_domain }}
|
||||
}
|
||||
|
||||
namespace inbox {
|
||||
inbox = yes
|
||||
|
||||
mailbox Drafts {
|
||||
special_use = \Drafts
|
||||
auto = subscribe
|
||||
}
|
||||
mailbox Junk {
|
||||
special_use = \Junk
|
||||
auto = subscribe
|
||||
}
|
||||
mailbox Trash {
|
||||
special_use = \Trash
|
||||
auto = subscribe
|
||||
}
|
||||
mailbox Sent {
|
||||
special_use = \Sent
|
||||
auto = subscribe
|
||||
}
|
||||
mailbox "Sent Messages" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Archive" {
|
||||
special_use = \Archive
|
||||
auto = subscribe
|
||||
}
|
||||
}
|
||||
|
||||
protocol sieve {
|
||||
}
|
||||
|
||||
|
@ -103,18 +141,6 @@ plugin {
|
|||
sieve_before = /etc/dovecot/global_script/
|
||||
}
|
||||
|
||||
plugin {
|
||||
antispam_debug_target = syslog
|
||||
antispam_verbose_debug = 0
|
||||
antispam_backend = pipe
|
||||
antispam_spam = Junk;SPAM
|
||||
antispam_trash = Trash
|
||||
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
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# See man 5 jail.conf for details.
|
||||
#
|
||||
# [DEFAULT]
|
||||
# bantime = 3600
|
||||
# bantime = 1h
|
||||
#
|
||||
# [sshd]
|
||||
# enabled = true
|
||||
|
@ -44,10 +44,52 @@ before = paths-debian.conf
|
|||
# MISCELLANEOUS OPTIONS
|
||||
#
|
||||
|
||||
# "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
|
||||
# "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
|
||||
|
||||
# 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.
|
||||
|
@ -56,15 +98,18 @@ ignoreip = 127.0.0.1/8
|
|||
ignorecommand =
|
||||
|
||||
# "bantime" is the number of seconds that a host is banned.
|
||||
bantime = 600
|
||||
bantime = 10m
|
||||
|
||||
# A host is banned if it has generated "maxretry" during the last "findtime"
|
||||
# seconds.
|
||||
findtime = 600
|
||||
findtime = 10m
|
||||
|
||||
# "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.
|
||||
|
@ -113,10 +158,13 @@ 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
|
||||
filter = %(__name__)s[mode=%(mode)s]
|
||||
|
||||
|
||||
#
|
||||
|
@ -140,7 +188,7 @@ mta = sendmail
|
|||
# Default protocol
|
||||
protocol = tcp
|
||||
|
||||
# Specify chain where jumps would need to be added in iptables-* actions
|
||||
# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
|
||||
chain = INPUT
|
||||
|
||||
# Ports to be banned
|
||||
|
@ -161,51 +209,53 @@ banaction = iptables-multiport
|
|||
banaction_allports = iptables-allports
|
||||
|
||||
# The simplest action to take: ban only
|
||||
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report to the destemail.
|
||||
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"]
|
||||
action_mw = %(action_)s
|
||||
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
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"]
|
||||
action_mwl = %(action_)s
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
||||
#
|
||||
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
||||
# to the destemail.
|
||||
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"]
|
||||
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
|
||||
|
||||
# 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[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
|
||||
|
||||
# Report block via blocklist.de fail2ban reporting service API
|
||||
#
|
||||
# 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]
|
||||
# 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).
|
||||
#
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
# Report ban via badips.com, and use as blacklist
|
||||
# Report ban via abuseipdb.com.
|
||||
#
|
||||
# See BadIPsAction docstring in config/action.d/badips.py for
|
||||
# documentation for this action.
|
||||
# See action.d/abuseipdb.conf for usage example and details.
|
||||
#
|
||||
# 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"]
|
||||
action_abuseipdb = abuseipdb
|
||||
|
||||
# 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
|
||||
|
@ -223,15 +273,10 @@ action = %(action_)s
|
|||
|
||||
[sshd]
|
||||
|
||||
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.
|
||||
# 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
|
||||
|
@ -265,7 +310,7 @@ logpath = %(apache_error_log)s
|
|||
# for email addresses. The mail outputs are buffered.
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
bantime = 172800
|
||||
bantime = 48h
|
||||
maxretry = 1
|
||||
|
||||
|
||||
|
@ -301,7 +346,7 @@ maxretry = 2
|
|||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
maxretry = 1
|
||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||
ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot <ip>
|
||||
|
||||
|
||||
[apache-modsecurity]
|
||||
|
@ -321,12 +366,15 @@ maxretry = 1
|
|||
[openhab-auth]
|
||||
|
||||
filter = openhab
|
||||
action = iptables-allports[name=NoAuthFailures]
|
||||
banaction = %(banaction_allports)s
|
||||
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
|
||||
|
||||
|
@ -342,8 +390,10 @@ 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
|
||||
|
@ -377,6 +427,8 @@ 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]
|
||||
|
@ -426,11 +478,13 @@ 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]
|
||||
|
@ -513,27 +567,29 @@ logpath = %(vsftpd_log)s
|
|||
# ASSP SMTP Proxy Jail
|
||||
[assp]
|
||||
|
||||
port = smtp,submission
|
||||
port = smtp,465,submission
|
||||
logpath = /root/path/to/assp/logs/maillog.txt
|
||||
|
||||
|
||||
[courier-smtp]
|
||||
|
||||
port = smtp,submission
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix]
|
||||
|
||||
port = smtp,submission
|
||||
# To use another modes set filter parameter "mode" in jail.local:
|
||||
mode = more
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[postfix-rbl]
|
||||
|
||||
port = smtp,submission
|
||||
filter = postfix[mode=rbl]
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
maxretry = 1
|
||||
|
@ -541,14 +597,17 @@ maxretry = 1
|
|||
|
||||
[sendmail-auth]
|
||||
|
||||
port = submission,smtp
|
||||
port = submission,465,smtp
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[sendmail-reject]
|
||||
|
||||
port = smtp,submission
|
||||
# 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
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
@ -556,7 +615,7 @@ backend = %(syslog_backend)s
|
|||
[qmail-rbl]
|
||||
|
||||
filter = qmail
|
||||
port = smtp,submission
|
||||
port = smtp,465,submission
|
||||
logpath = /service/qmail/log/main/current
|
||||
|
||||
|
||||
|
@ -564,14 +623,14 @@ logpath = /service/qmail/log/main/current
|
|||
# but can be set by syslog_facility in the dovecot configuration.
|
||||
[dovecot]
|
||||
|
||||
port = pop3,pop3s,imap,imaps,submission,sieve
|
||||
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[sieve]
|
||||
|
||||
port = smtp,submission
|
||||
port = smtp,465,submission
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
@ -583,20 +642,21 @@ logpath = %(solidpop3d_log)s
|
|||
|
||||
|
||||
[exim]
|
||||
|
||||
port = smtp,submission
|
||||
# see filter.d/exim.conf for further modes supported from filter:
|
||||
#mode = normal
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,submission
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
||||
port = imap,smtp,imaps
|
||||
port = imap,smtp,imaps,465
|
||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||
|
||||
|
||||
|
@ -607,14 +667,15 @@ logpath = /opt/kerio/mailserver/store/logs/security.log
|
|||
|
||||
[courier-auth]
|
||||
|
||||
port = smtp,submission,imaps,pop3,pop3s
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix-sasl]
|
||||
|
||||
port = smtp,submission,imap,imaps,pop3,pop3s
|
||||
filter = postfix[mode=auth]
|
||||
port = smtp,465,submission,imap,imaps,pop3,pop3s
|
||||
# You might consider monitoring /var/log/mail.warn instead if you are
|
||||
# running postfix since it would provide the same log lines at the
|
||||
# "warn" level but overall at the smaller filesize.
|
||||
|
@ -631,7 +692,7 @@ backend = %(syslog_backend)s
|
|||
|
||||
[squirrelmail]
|
||||
|
||||
port = smtp,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
|
||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||
|
||||
|
||||
|
@ -684,8 +745,8 @@ logpath = /var/log/named/security.log
|
|||
[nsd]
|
||||
|
||||
port = 53
|
||||
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]
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/nsd.log
|
||||
|
||||
|
||||
|
@ -696,9 +757,8 @@ logpath = /var/log/nsd.log
|
|||
[asterisk]
|
||||
|
||||
port = 5060,5061
|
||||
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"]
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/asterisk/messages
|
||||
maxretry = 10
|
||||
|
||||
|
@ -706,16 +766,22 @@ maxretry = 10
|
|||
[freeswitch]
|
||||
|
||||
port = 5060,5061
|
||||
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"]
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
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-warning = 2
|
||||
# log-warnings = 2
|
||||
#
|
||||
# for syslog (daemon facility)
|
||||
# [mysqld_safe]
|
||||
|
@ -731,6 +797,14 @@ 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
|
||||
|
@ -749,8 +823,8 @@ logpath = /var/log/mongodb/mongodb.log
|
|||
|
||||
logpath = /var/log/fail2ban.log
|
||||
banaction = %(banaction_allports)s
|
||||
bantime = 604800 ; 1 week
|
||||
findtime = 86400 ; 1 day
|
||||
bantime = 1w
|
||||
findtime = 1d
|
||||
|
||||
|
||||
# Generic filter for PAM. Has to be used with action which bans all
|
||||
|
@ -786,11 +860,31 @@ logpath = /var/log/ejabberd/ejabberd.log
|
|||
[counter-strike]
|
||||
|
||||
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 = %(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]
|
||||
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
|
||||
|
||||
# consider low maxretry and a long bantime
|
||||
# nobody except your own Nagios server should ever probe nrpe
|
||||
|
@ -824,7 +918,9 @@ filter = apache-pass[knocking_url="%(knocking_url)s"]
|
|||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
bantime = 3600
|
||||
action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
|
||||
actionstart_on_demand=false, actionrepair_on_unban=true]
|
||||
bantime = 1h
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
||||
|
@ -832,8 +928,8 @@ findtime = 1
|
|||
[murmur]
|
||||
# AKA mumble-server
|
||||
port = 64738
|
||||
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]
|
||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
|
||||
%(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
|
||||
logpath = /var/log/mumble-server/mumble-server.log
|
||||
|
||||
|
||||
|
@ -851,5 +947,34 @@ 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
|
||||
|
|
|
@ -31,3 +31,12 @@ 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
|
||||
|
|
3
conf/fail2ban/yunohost-portal.conf
Normal file
3
conf/fail2ban/yunohost-portal.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
[Definition]
|
||||
failregex = ^<HOST> -.*\"POST /yunohost/portalapi/login HTTP/\d.\d\" 401
|
||||
ignoreregex =
|
|
@ -1,24 +1,3 @@
|
|||
# Fail2Ban configuration file
|
||||
#
|
||||
# Author: Adrien Beudin
|
||||
#
|
||||
# $Revision: 2 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
# 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
|
||||
#
|
||||
failregex = ^<HOST> -.*\"POST /yunohost/api/login HTTP/\d.\d\" 401
|
||||
ignoreregex =
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
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"
|
|
@ -1,123 +0,0 @@
|
|||
-- ** 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"
|
|
@ -1,270 +0,0 @@
|
|||
-- 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;
|
|
@ -1,90 +0,0 @@
|
|||
-- 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));
|
|
@ -1,87 +0,0 @@
|
|||
-- 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);
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
-- 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);
|
|
@ -1,162 +0,0 @@
|
|||
-- 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;
|
|
@ -1,6 +1,6 @@
|
|||
location ^~ '/.well-known/acme-challenge/'
|
||||
{
|
||||
default_type "text/plain";
|
||||
alias /tmp/acme-challenge-public/;
|
||||
alias /var/www/.well-known/acme-challenge-public/;
|
||||
gzip off;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
# 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) {
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
# 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
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
location / {
|
||||
return 302 https://$http_host/yunohost/admin;
|
||||
return 302 https://$host/yunohost/admin;
|
||||
}
|
||||
|
|
|
@ -3,16 +3,16 @@ ssl_session_cache shared:SSL:50m; # about 200000 sessions
|
|||
ssl_session_tickets off;
|
||||
|
||||
{% if compatibility == "modern" %}
|
||||
# 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
|
||||
# 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
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
{% else %}
|
||||
# Ciphers with intermediate compatibility
|
||||
# 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
|
||||
# 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
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# Pre-defined FFDHE group (RFC 7919)
|
||||
|
@ -26,7 +26,7 @@ ssl_dhparam /usr/share/yunohost/ffdhe2048.pem;
|
|||
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
||||
# https://observatory.mozilla.org/
|
||||
{% if experimental == "True" %}
|
||||
more_set_headers "Content-Security-Policy : upgrade-insecure-requests; default-src https: data: blob: ; object-src https: data: 'unsafe-inline'; style-src https: data: 'unsafe-inline' ; script-src https: data: 'unsafe-inline' 'unsafe-eval'";
|
||||
more_set_headers "Content-Security-Policy : upgrade-insecure-requests; default-src https: data: blob: ; object-src https: data: 'unsafe-inline'; style-src https: data: 'unsafe-inline' ; script-src https: data: 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:;";
|
||||
{% else %}
|
||||
more_set_headers "Content-Security-Policy : upgrade-insecure-requests";
|
||||
{% endif %}
|
||||
|
|
|
@ -6,14 +6,14 @@ map $http_upgrade $connection_upgrade {
|
|||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name {{ domain }}{% if xmpp_enabled == "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %};
|
||||
server_name {{ domain }};
|
||||
|
||||
access_by_lua_file /usr/share/ssowat/access.lua;
|
||||
|
||||
include /etc/nginx/conf.d/acme-challenge.conf.inc;
|
||||
|
||||
location ^~ '/.well-known/ynh-diagnosis/' {
|
||||
alias /tmp/.well-known/ynh-diagnosis/;
|
||||
alias /var/www/.well-known/ynh-diagnosis/;
|
||||
}
|
||||
|
||||
{% if mail_enabled == "True" %}
|
||||
|
@ -25,7 +25,7 @@ server {
|
|||
{# Note that this != "False" is meant to be failure-safe, in the case the redrect_to_https would happen to contain empty string or whatever value. We absolutely don't want to disable the HTTPS redirect *except* when it's explicitly being asked to be disabled. #}
|
||||
{% if redirect_to_https != "False" %}
|
||||
location / {
|
||||
return 301 https://$http_host$request_uri;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
{# The app config snippets are not included in the HTTP conf unless HTTPS redirect is disabled, because app's location may blocks will conflict or bypass/ignore the HTTPS redirection. #}
|
||||
{% else %}
|
||||
|
@ -56,7 +56,7 @@ server {
|
|||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
|
||||
resolver 127.0.0.1 127.0.1.1 valid=300s;
|
||||
resolver 1.1.1.1 9.9.9.9 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
{% endif %}
|
||||
|
||||
|
@ -78,48 +78,3 @@ 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 127.0.0.1 127.0.1.1 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 %}
|
||||
|
|
|
@ -4,7 +4,7 @@ location /yunohost/api/ {
|
|||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
{% if webadmin_allowlist_enabled == "True" %}
|
||||
{% for ip in webadmin_allowlist.split(',') %}
|
||||
|
@ -23,3 +23,24 @@ 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;
|
||||
}
|
||||
|
|
21
conf/nginx/yunohost_sso.conf.inc
Normal file
21
conf/nginx/yunohost_sso.conf.inc
Normal file
|
@ -0,0 +1,21 @@
|
|||
# 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:;";
|
||||
}
|
31
conf/opendkim/opendkim.conf
Normal file
31
conf/opendkim/opendkim.conf
Normal file
|
@ -0,0 +1,31 @@
|
|||
# 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
|
|
@ -30,8 +30,8 @@ smtpd_tls_chain_files =
|
|||
tls_server_sni_maps = hash:/etc/postfix/sni
|
||||
|
||||
{% if compatibility == "intermediate" %}
|
||||
# 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
|
||||
# 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
|
||||
|
||||
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
|
||||
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
||||
{% else %}
|
||||
# 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
|
||||
# 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
|
||||
|
||||
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
||||
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
|
||||
|
@ -100,14 +100,18 @@ message_size_limit = 35914708
|
|||
|
||||
# Virtual Domains Control
|
||||
virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf
|
||||
virtual_mailbox_maps = ldap:/etc/postfix/ldap-accounts.cf
|
||||
virtual_mailbox_maps = ldap:/etc/postfix/ldap-accounts.cf,hash:/etc/postfix/app_senders_login_maps
|
||||
virtual_mailbox_base =
|
||||
virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf,ldap:/etc/postfix/ldap-groups.cf
|
||||
virtual_alias_domains =
|
||||
virtual_minimum_uid = 100
|
||||
virtual_uid_maps = static:vmail
|
||||
virtual_gid_maps = static:mail
|
||||
smtpd_sender_login_maps= ldap:/etc/postfix/ldap-accounts.cf
|
||||
smtpd_sender_login_maps = unionmap:{
|
||||
# Regular Yunohost accounts
|
||||
ldap:/etc/postfix/ldap-accounts.cf,
|
||||
# Extra maps for app system users who need to send emails
|
||||
hash:/etc/postfix/app_senders_login_maps }
|
||||
|
||||
# Dovecot LDA
|
||||
virtual_transport = dovecot
|
||||
|
@ -178,9 +182,10 @@ 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}
|
||||
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} {auth_type}
|
||||
milter_protocol = 6
|
||||
smtpd_milters = inet:localhost:11332
|
||||
smtpd_milters = inet:localhost:8891
|
||||
non_smtpd_milters = inet:localhost:8891
|
||||
|
||||
# Skip email without checking if milter has died
|
||||
milter_default_action = accept
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
# This maps domain to certificates to properly handle multi-domain context
|
||||
# (also we need a comment in this file such that it's never empty to prevent regenconf issues)
|
||||
{% for domain in domain_list.split() %}{{ domain }} /etc/yunohost/certs/{{ domain }}/key.pem /etc/yunohost/certs/{{ domain }}/crt.pem
|
||||
{% endfor %}
|
|
@ -1,16 +0,0 @@
|
|||
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";
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# Metrics settings
|
||||
# This define overridden options.
|
||||
|
||||
actions {
|
||||
reject = 21;
|
||||
add_header = 8;
|
||||
greylist = 4;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
use = ["spam-header"];
|
||||
|
||||
routines {
|
||||
spam-header {
|
||||
header = "X-Spam";
|
||||
value = "Yes";
|
||||
remove = 1;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
require ["fileinto"];
|
||||
if header :is "X-Spam" "Yes" {
|
||||
fileinto "Junk";
|
||||
}
|
|
@ -159,7 +159,7 @@ olcAccess: {2}to dn.base=""
|
|||
# can read everything.
|
||||
olcAccess: {3}to *
|
||||
by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
|
||||
by group/groupOfNames/member.exact="cn=admins,ou=groups,dc=yunohost,dc=org" write
|
||||
by group/groupOfNamesYnh/member.exact="cn=admins,ou=groups,dc=yunohost,dc=org" write
|
||||
by * read
|
||||
#
|
||||
olcAddContentAcl: FALSE
|
||||
|
|
|
@ -56,7 +56,6 @@ 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
|
||||
|
@ -75,17 +74,6 @@ 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
|
||||
|
|
|
@ -64,7 +64,7 @@ PasswordAuthentication no
|
|||
{% endif %}
|
||||
|
||||
# Post-login stuff
|
||||
Banner /etc/issue.net
|
||||
# Banner none
|
||||
PrintMotd no
|
||||
PrintLastLog yes
|
||||
ClientAliveInterval 60
|
||||
|
|
|
@ -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,DNS:xmpp-upload.yunohost.org
|
||||
subjectAltName=DNS:yunohost.org,DNS:www.yunohost.org,DNS:ns.yunohost.org
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
|
|
|
@ -8,11 +8,6 @@ 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
|
||||
|
@ -28,21 +23,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@13-main'
|
||||
actual_systemd_service: 'postgresql@15-main'
|
||||
category: database
|
||||
ignore_if_package_is_not_installed: postgresql-13
|
||||
ignore_if_package_is_not_installed: postgresql-15
|
||||
redis-server:
|
||||
log: /var/log/redis/redis-server.log
|
||||
category: database
|
||||
rspamd:
|
||||
log: /var/log/rspamd/rspamd.log
|
||||
category: email
|
||||
slapd:
|
||||
category: database
|
||||
test_conf: slapd -Tt
|
||||
|
@ -51,6 +46,9 @@ 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
|
||||
|
@ -60,21 +58,6 @@ 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
|
||||
|
|
48
conf/yunohost/yunohost-portal-api.service
Normal file
48
conf/yunohost/yunohost-portal-api.service
Normal file
|
@ -0,0 +1,48 @@
|
|||
[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
|
491
debian/changelog
vendored
491
debian/changelog
vendored
|
@ -4,6 +4,496 @@ yunohost (12.0.0) unstable; urgency=low
|
|||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 04 May 2023 20:30:19 +0200
|
||||
|
||||
yunohost (11.2.21.2) stable; urgency=low
|
||||
|
||||
- bullseye->bookworm migration: tweak message to reflect the fact that metronome and rspamd will be applications starting with bookworm (64c8d9e8)
|
||||
- helpers/apt: unbound variable (8a65053a)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 15 Jul 2024 23:07:08 +0200
|
||||
|
||||
yunohost (11.2.21.1) stable; urgency=low
|
||||
|
||||
- helpers2.1: forgot to patch ynh_remove_fpm_config -> ynh_config_remove_phpfpm (bb20020c)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 15 Jul 2024 22:13:39 +0200
|
||||
|
||||
yunohost (11.2.21) stable; urgency=low
|
||||
|
||||
- log: optimize log list perf by creating a 'cache' symlink pointing to the log's parent ([#1907](http://github.com/YunoHost/yunohost/pull/1907))
|
||||
- log: small hack when dumping log right after script failure, prevent a weird edge case where it'll dump the log of the resource provisioning instead of the script (1bb81e8f)
|
||||
- debian: Bullseye->Bookworm migration ('hidden' but easier to test) ([#1759](http://github.com/YunoHost/yunohost/pull/1759), ab8e0e66, e54e99bf)
|
||||
- helpers/apt: rely on simpler dpkg-deb --build rather than equivs to create .deb for app virtual dependencies (f6fbd69c, 8be726b9)
|
||||
- helpers/apt: Support apt repositories with [trusted=yes] ([#1903](http://github.com/YunoHost/yunohost/pull/1903))
|
||||
- backups: one should be able to restore a backup archive by providing a path to the archive without moving it to /home/yunohost.backup/archives/ (c8a18129, b266e398)
|
||||
- backups: yunohost should not ask confirmation that 'YunoHost is already installed' when restoring only apps (9c22d36c)
|
||||
- i18n: translate _diagnosis_ignore function ([#1894](http://github.com/YunoHost/yunohost/pull/1894))
|
||||
- i18n: Translations updated for Basque, Catalan, French, Galician, German, Indonesian, Japanese, Russian, Spanish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, Anonymous, cjdw, Félix Piédallu, Ivan Davydov, José M, Kayou, OniriCorpe, ppr, Zwiebel)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 15 Jul 2024 16:22:26 +0200
|
||||
|
||||
yunohost (11.2.20.2) stable; urgency=low
|
||||
|
||||
- Fix service enable/disable auto-ignoring diagnosis entries ([#1886](http://github.com/YunoHost/yunohost/pull/1886))
|
||||
|
||||
Thanks to all contributors <3 ! (OniriCorpe)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 03 Jul 2024 21:51:50 +0200
|
||||
|
||||
yunohost (11.2.20.1) stable; urgency=low
|
||||
|
||||
- helpers2.1: typo (1ed56952e)
|
||||
- helpers2.1: add unit tests (92807afb1)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 01 Jul 2024 23:38:29 +0200
|
||||
|
||||
yunohost (11.2.20) stable; urgency=low
|
||||
|
||||
- helpers2.1: fix automigration of phpversion to php_version (3f973669)
|
||||
- helpers2.1: change source patches location + raise an error instead of a warning when a patch fails to apply on CI (a48bfa67)
|
||||
- helpers2.1: when using ynh_die, also return the error via YNH_STDRETURN such that it can be obtained from the python and displayed in the main error message, to increase the chance that people may read it and have something more useful than "An error happened in the script" (f2b5f0f2)
|
||||
- helpers2.1: remove the ynh_clean_setup mechanism underused/useless.. (1c62960e)
|
||||
- helpers2.1: switch to posisional args for ynh_multimedia_addaccess because that's what 99% of apps already do (ef622ffe)
|
||||
- helpers2.1: add support for downloading .tar files ([#1889](http://github.com/YunoHost/yunohost/pull/1889))
|
||||
- services/diagnosis: automatically ignore the service in diagnosis if it has been deactivated with the ynh cli ([#1886](http://github.com/YunoHost/yunohost/pull/1886))
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, OniriCorpe, Sebastian Gumprich)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 01 Jul 2024 18:46:52 +0200
|
||||
|
||||
yunohost (11.2.19) stable; urgency=low
|
||||
|
||||
- apps: tweaks to be more robust and prevent the stupid flood of 'sh: 0: getcwd() failed: No such file or directory' when running an app upgrade/remove from /var/www/$app, sometimes making it look like the upgrade failed when it didnt (a349fc03)
|
||||
- apps: be more robust when an app upgrade succeeds but for some reason is marked with 'broke the system' ... ending up in inconsistent state between the app settings vs the app scritpts (for example in v1->v2 transitions but not only) (e5b57590)
|
||||
- helpers2.1: Fix getopts error handling ... (3e1c9eba)
|
||||
- helpers2.1: also run _ynh_apply_default_permissions in ynh_restore to be consistent (also because the user uid on the new system may be different than in the archive etc) (eee84c5f)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 29 Jun 2024 23:55:52 +0200
|
||||
|
||||
yunohost (11.2.18) stable; urgency=low
|
||||
|
||||
- helpers2.1: Rework _ynh_apply_default_permissions to hopefully remove the necessity to chown/chmod in the app scripts ([#1883](http://github.com/YunoHost/yunohost/pull/1883))
|
||||
- helpers2.1: in logrotate, make sure to also chown $app the log dir (1dfc47d1d)
|
||||
- helpers2.1: forgot to rename the apt call in mongodb helpers (7b2959a3e)
|
||||
- helpers2.1: in ynh_safe_rm, check if target is not a broken symlink before erorring out ([#1716](http://github.com/YunoHost/yunohost/pull/1716))
|
||||
|
||||
Thanks to all contributors <3 ! (Félix Piédallu)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 29 Jun 2024 18:05:04 +0200
|
||||
|
||||
yunohost (11.2.17.1) stable; urgency=low
|
||||
|
||||
- helpers2.1: fix __PATH__/ handling (997388dc)
|
||||
- ci: Fix helpers 2.1 doc location (7347b08e)
|
||||
- helpers/doc: De-hide some helpers v1 in documentation now that the structure is less bloated sort of ? (2a7fefae)
|
||||
- helpers/doc: fix detail block, cant use the HTML <details> because grav doesnt interpret markdown in it (feb9a095)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 25 Jun 2024 14:19:58 +0200
|
||||
|
||||
yunohost (11.2.17) stable; urgency=low
|
||||
|
||||
- helpers: Misc cleaning / reorganizing to prepare new doc (2895d4d9)
|
||||
- helpers: rework helper doc now that we have multiple versions of helpers in parallel + improve structure (group helper file in categories) (094cd9dd)
|
||||
- helpers/mongo: less noisy output when checking the avx flag is here in /proc/cpuinfo (2af4c157)
|
||||
- apps/helpers2.1: fix app env in resource upgrade context ending up in incorrect helper version being used (ed426f05)
|
||||
- helpers2.1: forgot to propagate the 'goenv latest' fix from helpers v1 (d8c3ff4c)
|
||||
- helpers2.1: drop ynh_apps helper because only a single app is using it ... (1fb80e5d)
|
||||
- helpers2.1: other typo fixes
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 24 Jun 2024 22:36:32 +0200
|
||||
|
||||
yunohost (11.2.16) stable; urgency=low
|
||||
|
||||
- apps/logs: fix some information not being redacted because of the packaging v2 flows (a25033bb)
|
||||
- logs: misc ad-hoc tweaks to limit the noise in log sharing (06c8fbc8)
|
||||
- helpers: (1/2/2.1) add a new ynh_app_setting_set_default to replace the unecessarily complex 'if [ -z ${foo:-} ]' trick ([#1873](http://github.com/YunoHost/yunohost/pull/1873))
|
||||
- helpers2.1: drop unused 'local source' mechanism from ynh_setup_source (dd8db188)
|
||||
- helpers2.1: fix positional arg parsing in ynh_psql_create_user (e5585136)
|
||||
- helpers2.1: rework the fpm usage/footprint madness ([#1874](http://github.com/YunoHost/yunohost/pull/1874))
|
||||
- helpers2.1: fix ynh_config_add_logrotate when no arg is passed (3942ea12)
|
||||
- helpers2.1: sudo -u$app -> sudo -u $app (d4857834)
|
||||
- helpers2.1: change default timeout of ynh_systemctl to 60s instead of 300s (262453f1)
|
||||
- helpers2.1: display 100 lines instead of 20 in CI context when service fails to start (9298738d)
|
||||
- helpers2.1: when using ynh_systemctl to reload/start/restart a service with a wait_until and it timesout, handle it as a failure rather than keep going (b3409729)
|
||||
- helpers2.1: for some reason sudo -E doesn't preserve PATH even though it's exported, so we gotta explicitly use --preserve-env=PATH (5f6df6a8)
|
||||
- helpers2.1: var rename / cosmetic etc for nodejs/ruby/go version and install directories (2b1f7426)
|
||||
- i18n: Translations updated for Basque, Slovak
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, Jose Riha, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 23 Jun 2024 15:30:22 +0200
|
||||
|
||||
yunohost (11.2.15) stable; urgency=low
|
||||
|
||||
- apps: new experimentals "2.1" helpers ([#1855](http://github.com/YunoHost/yunohost/pull/1855))
|
||||
- apps: when removing an app with --purge, also remove /var/log/{app}
|
||||
- apps: drop clumsy auto-update of nodejs via cron job which fills up disk space with nodejs copies and doesnt actually restart the app services...
|
||||
- apps: fix apt resources when multiple extras are set ([#1869](http://github.com/YunoHost/yunohost/pull/1869))
|
||||
- mail: allow aliases for sender addresses of apps ([#1843](http://github.com/YunoHost/yunohost/pull/1843))
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, Chris Vogel, Félix Piédallu)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 20 Jun 2024 21:20:47 +0200
|
||||
|
||||
yunohost (11.2.14.1) stable; urgency=low
|
||||
|
||||
- helpers: Fix typo in ynh_read_manifest documentation ([#1866](http://github.com/YunoHost/yunohost/pull/1866))
|
||||
- helpers/go: fix goenv call ([#1868](http://github.com/YunoHost/yunohost/pull/1868))
|
||||
|
||||
Thanks to all contributors <3 ! (Chris Vogel, clecle226, Félix Piédallu, OniriCorpe)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 10 Jun 2024 12:34:25 +0200
|
||||
|
||||
yunohost (11.2.14) testing; urgency=low
|
||||
|
||||
- helpers/go: fix missing git fetch (5676a7275)
|
||||
|
||||
-- Félix Piédallu <felix@piedallu.me> Wed, 05 Jun 2024 15:52:06 +0200
|
||||
|
||||
yunohost (11.2.13) stable; urgency=low
|
||||
|
||||
- helpers: add a --jinja option to ynh_add_config ([#1851](http://github.com/YunoHost/yunohost/pull/1851))
|
||||
- helpers: add mongodb helpers ([#1844](http://github.com/YunoHost/yunohost/pull/1844))
|
||||
- helpers: update getopts to accept arguments that are valid arguments to echo ([#1847](http://github.com/YunoHost/yunohost/pull/1847))
|
||||
- helpers: create versionned directories of the helpers ([#1717](http://github.com/YunoHost/yunohost/pull/1717))
|
||||
- helpers: fix goenv broken when checking out latest master commit ([#1863](http://github.com/YunoHost/yunohost/pull/1863))
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, Chris Vogel, Félix Piédallu, Josué Tille, Salamandar, tituspijean)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 04 Jun 2024 16:43:42 +0200
|
||||
|
||||
yunohost (11.2.12) stable; urgency=low
|
||||
|
||||
- doc: Remove internal/packagingv1 helpers from helpers doc ([#1832](http://github.com/YunoHost/yunohost/pull/1832))
|
||||
- helpers: Document ynh_add_source --full_replace=1 ([#1834](http://github.com/YunoHost/yunohost/pull/1834))
|
||||
- helpers/apt: Actually remove the newly added repo. ([#1835](http://github.com/YunoHost/yunohost/pull/1835))
|
||||
- ldap: fix ldap write access for admin users ([#1836](http://github.com/YunoHost/yunohost/pull/1836))
|
||||
- helpers: Add Go Helper to the core ([#1837](http://github.com/YunoHost/yunohost/pull/1837))
|
||||
- helpers: Prevent yet another Node and Corepack madness ([#1842](http://github.com/YunoHost/yunohost/pull/1842))
|
||||
- certs: fix renew cert for sub subdomain ([#1819](http://github.com/YunoHost/yunohost/pull/1819))
|
||||
- cli: [enh] Implement 'yunohost log show last' to display the last log file. ([#1805](http://github.com/YunoHost/yunohost/pull/1805))
|
||||
- helpers: Add redis and ruby helpers ([#1838](http://github.com/YunoHost/yunohost/pull/1838))
|
||||
- [i18n] Translations updated for Basque, Catalan, Chinese (Simplified), Esperanto, French, Galician, German, Indonesian, Italian, Japanese, Persian, Slovak, Spanish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (alexAubin, BELLAHBIB Ayoub, eric_G, José M, Kayou, manor-tile, Mateusz, rosbeef andino, selfhoster1312, tituspijean, xabirequejo, Yann Autissier)
|
||||
|
||||
-- OniriCorpe <oniricorpe@yunohost.org> Mon, 20 May 2024 00:02:47 +0200
|
||||
|
||||
yunohost (11.2.11.3) stable; urgency=low
|
||||
|
||||
- fix: edge case when parsing app upstream version from resource manager (5e4e59a1, a5560c30)
|
||||
- helpers: fix 'ls: cannot access <folder> No such file or directory' errors on CI (537699ca)
|
||||
- maintenance: Upgrade n to 9.2.3 ([#1818](http://github.com/YunoHost/yunohost/pull/1818))
|
||||
|
||||
Thanks to all contributors <3 ! (Alexandre Aubin, OniriCorpe)
|
||||
|
||||
-- tituspijean <titus+yunohost@pijean.ovh> Sun, 21 Apr 2024 19:10:02 +0200
|
||||
|
||||
yunohost (11.2.11.2) stable; urgency=low
|
||||
|
||||
- More oopsies (22b30c79)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 11 Apr 2024 16:03:20 +0200
|
||||
|
||||
yunohost (11.2.11.1) stable; urgency=low
|
||||
|
||||
- Missing import oopsi (29c597ed)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 11 Apr 2024 14:32:52 +0200
|
||||
|
||||
yunohost (11.2.11) stable; urgency=low
|
||||
|
||||
- maintenance: make_changelog.sh enhancements ([#1790](http://github.com/YunoHost/yunohost/pull/1790))
|
||||
- maintenance: switch from gitlab CI to github actions for autoblacking code ([#1800](http://github.com/YunoHost/yunohost/pull/1800))
|
||||
- readme: add images alt text, fix some links and some markdown formating ([#1802](http://github.com/YunoHost/yunohost/pull/1802))
|
||||
- doc: fix markdown for autogenerated doc for app helpers and resources ([#1793](http://github.com/YunoHost/yunohost/pull/1793))
|
||||
- helpers/apt: Do not wait for dpkg lock when calling ynh_package_is_installed ([#1811](http://github.com/YunoHost/yunohost/pull/1811))
|
||||
- helpers/misc: Protect more path on ynh secure remove ([#1810](http://github.com/YunoHost/yunohost/pull/1810))
|
||||
- perf: add cache for system utils that fetch debian_version, debian_version_id, system_arch, system_virt (85f83af8)
|
||||
- app resources: be able to use __APP__, __YNH_ARCH__ and __YNH_DEBIAN_VERSION__, __YNH_DEBIAN_VERSION_ID__ in properties ([#1751](http://github.com/YunoHost/yunohost/pull/1751), a3ab7c91)
|
||||
- app configpanels: add settings in bash context when running config scripts (c9d570e6, 006318ef)
|
||||
- app configpanels: fix quoting issue when returning values from config scripts ([#1789](http://github.com/YunoHost/yunohost/pull/1789))
|
||||
- i18n: Translations updated for Arabic, Basque, Catalan, Chinese (Simplified), Czech, Dutch, English, Esperanto, French, Galician, German, Hindi, Indonesian, Italian, Japanese, Norwegian Bokmål, Occitan, Persian, Polish, Portuguese, Russian, Slovak, Spanish, Telugu, Turkish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (Bram, Christian Wehrli, Félix Piédallu, Francescc, José M, Josué Tille, Kayou, OniriCorpe, ppr, Tagada, tituspijean, xabirequejo, xaloc33, yolateng0)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 11 Apr 2024 12:24:07 +0200
|
||||
|
||||
yunohost (11.2.10.3) stable; urgency=low
|
||||
|
||||
- fix: latest release was tagged 'testing' by error
|
||||
|
||||
Thanks to all contributors <3 ! (Alexandre Aubin, Tagada, OniriCorpe)
|
||||
|
||||
-- OniriCorpe <oniricorpe@yunohost.org> Thu, 29 Feb 2024 23:49:11 +0100
|
||||
|
||||
yunohost (11.2.10.2) stable; urgency=low
|
||||
|
||||
- docs: add autoupdate.version_regex to the doc ([#1781](http://github.com/YunoHost/yunohost/pull/1781))
|
||||
- chores: update actions/checkout & peter-evans/create-pull-request to nodejs20 ([#1784](http://github.com/YunoHost/yunohost/pull/1784))
|
||||
- apps: fix readonly questions at install (display_text, etc) ([#1786](http://github.com/YunoHost/yunohost/pull/1786))
|
||||
- chores: upgrade n to v9.2.1 ([#1783](http://github.com/YunoHost/yunohost/pull/1783))
|
||||
- helpers/logrotate: fix logs folder permissions ([#1787](http://github.com/YunoHost/yunohost/pull/1787))
|
||||
- fix: list root ssh keys ([#1788](http://github.com/YunoHost/yunohost/pull/1788))
|
||||
- [i18n] Translations updated for German
|
||||
|
||||
Thanks to all contributors <3 ! (Alexandre Aubin, Félix Piédallu, Kay0u, ljf (zamentur), Tagada, tituspijean, YunoHost Bot)
|
||||
|
||||
-- OniriCorpe <oniricorpe@yunohost.org> Thu, 29 Feb 2024 23:49:11 +0100
|
||||
|
||||
yunohost (11.2.10.1) stable; urgency=low
|
||||
|
||||
- apps/autoupdate: update docs ([#1776](http://github.com/YunoHost/yunohost/pull/1776))
|
||||
- fix: sury apt key/purge all expired apt keys ([#1777](http://github.com/YunoHost/yunohost/pull/1777))
|
||||
- helpers/logrotate: fix logs folders perms ([#1774](http://github.com/YunoHost/yunohost/pull/1774))
|
||||
- [i18n] Translations updated for Catalan, Italian
|
||||
|
||||
Thanks to all contributors <3 ! (Alexandre Aubin, Bram, Francescc, Kayou, OniriCorpe, Tagada, Tommi, yunohost-bot)
|
||||
|
||||
-- Kay0u <pierre@kayou.io> Tue, 20 Feb 2024 23:33:20 +0100
|
||||
|
||||
yunohost (11.2.10) stable; urgency=low
|
||||
|
||||
- helpers: document --after= in for ynh_read_var_in_file and ynh_write_var_in_file ([#1758](https://github.com/yunohost/yunohost/pull/1758))
|
||||
- resources: document changelog link for latest_github_release ([#1760](https://github.com/yunohost/yunohost/pull/1760))
|
||||
- apps/helpers: Reword YNH_APP_UPGRADE_TYPE ([#1762](https://github.com/yunohost/yunohost/pull/1762))
|
||||
- app shells: auto-source venv for python apps ([#1756](https://github.com/yunohost/yunohost/pull/1756))
|
||||
- tools: Add a 'yunohost tools basic-space-cleanup' command ([#1761](https://github.com/yunohost/yunohost/pull/1761))
|
||||
- certs/xmpp: Fix DNS suffix edge case during XMPP certificate setup ([#1763](https://github.com/yunohost/yunohost/pull/1763))
|
||||
- helpers/php: quote vars to avoid stupid issues with name in path which may happen in backup restore context... (05f7c3a3b)
|
||||
- multimedia: fix again edgecase where setfacl crashes because of broken symlinks.. (1ce606d46)
|
||||
- helpers: disable super verbose logging during ynh_replace_vars poluting logs, it's kinda stable now... (981956051, c2af17667)
|
||||
- apps: people insist on trying to install Nextcloud after creating a user called nextcloud ... So let's check this stupid case (fc12cb198)
|
||||
- apps: fix port reuse during provisionning ([#1769](https://github.com/yunohost/yunohost/pull/1769))
|
||||
- configpanels: some helpers behavior depend on YNH_APP_PACKAGING_FORMAT which is not set when calling the config script... (077b745d6)
|
||||
- global settings: Add warning regarding ssh ports below 1024 ([#1765](https://github.com/yunohost/yunohost/pull/1765))
|
||||
- global settings: mention cidr notation support in webadmin allowlist help ([#1770](https://github.com/yunohost/yunohost/pull/1770))
|
||||
- chores: update copyright headers to 2024 using maintenance/update_copyright_headers.sh (a44ea1414)
|
||||
- i18n: remove stale i18n strings, fix format inconsistencies (890fcee05, [#1764](https://github.com/yunohost/yunohost/pull/1764))
|
||||
- i18n: Translations updated for Arabic, Basque, Catalan, French, Galician, German, Slovak, Spanish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (Bram, Carlos Solís, Christian Wehrli, cube, Éric Gaspar, Félix Piédallu, Francescc, José M, Jose Riha, Lasse Gismo, ljf (zamentur), OniriCorpe, ppr, Saeba Ryo, tituspijean, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 09 Feb 2024 20:05:36 +0100
|
||||
|
||||
yunohost (11.2.9.1) stable; urgency=low
|
||||
|
||||
- helpers/utils: replace the damn ynh_die with a warning when patch fails to apply ... (0ed6769fc)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 28 Dec 2023 02:45:33 +0100
|
||||
|
||||
yunohost (11.2.9) stable; urgency=low
|
||||
|
||||
- users: Allow dots in usernames ([#1750](https://github.com/yunohost/yunohost/pull/1750))
|
||||
- ynh_setup_source: properly handle --keep for directories when the dir already exists in the new setup (8e3e78884)
|
||||
- ynh_setup_source: fix first source patches failure not triggering an error (770fdb686)
|
||||
- ynh_use_logrotate: Refactor this madness (308ed0e17)
|
||||
- systemutils: when checking debian version and system arch, redirect stderr to /dev/null to prevent stupid issues (830d7b47e)
|
||||
- mail/apps: add mailbox/IMAP support for apps that declared a system user with mail enabled (#1745)
|
||||
- mail: fix edge case bug with the postfix sni file when no domain has mail enabled (155418409)
|
||||
- i18n: Translations updated for Basque, Polish
|
||||
|
||||
Thanks to all contributors <3 ! (Josue-T, Kuba Bazan, ljf, selfhoster1312, xabirequejo, YapWC)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 27 Dec 2023 18:45:30 +0100
|
||||
|
||||
yunohost (11.2.8.2) stable; urgency=low
|
||||
|
||||
- Aleks forgot to remove pdb.set_trace ... (54a6a1b3)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 09 Dec 2023 18:26:10 +0100
|
||||
|
||||
yunohost (11.2.8.1) stable; urgency=low
|
||||
|
||||
- apps: fix change_url again, otherwise the lack of path_url default to the old path and fucks up the nginx regen (169c9214)
|
||||
- i18n: Translations updated for German
|
||||
|
||||
Thanks to all contributors <3 ! (Christian Wehrli)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 09 Dec 2023 15:56:20 +0100
|
||||
|
||||
yunohost (11.2.8) stable; urgency=low
|
||||
|
||||
- domains: also regen dovecot configuration when adding a domain (59875cae)
|
||||
- helpers/fail2ban: grep logpath is likely to match comments in the file that contain the word logpath... (26796807)
|
||||
- helpers: Further simplify the change url helper ([#1746](https://github.com/yunohost/yunohost/pull/1746))
|
||||
|
||||
Thanks to all contributors <3 ! (Josué Tille)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 05 Dec 2023 19:21:38 +0100
|
||||
|
||||
yunohost (11.2.7) stable; urgency=low
|
||||
|
||||
- helpers: fix fail2ban helper when using using --use_template arg ([#1743](https://github.com/yunohost/yunohost/pull/1743))
|
||||
- i18n: Translations updated for Basque, French, Galician
|
||||
|
||||
Thanks to all contributors <3 ! (José M, OniriCorpe, ppr, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 27 Nov 2023 14:13:54 +0100
|
||||
|
||||
yunohost (11.2.6) stable; urgency=low
|
||||
|
||||
- mail: Improve dovecots rspamd integration wrt junk/spam folder naming ([#1731](https://github.com/yunohost/yunohost/pull/1731))
|
||||
- mail: add redis database configuration in rspamd ([#1730](https://github.com/yunohost/yunohost/pull/1730))
|
||||
- mail: let dovecot create folders on first login ([#1735](https://github.com/yunohost/yunohost/pull/1735))
|
||||
- apps: Support packages_from_raw_bash in extra packages ([#1729](https://github.com/yunohost/yunohost/pull/1729))
|
||||
- apps/configpanel: support bind 'heritage', avoid repeating the same bind statement for multiple options ([#1706](https://github.com/yunohost/yunohost/pull/1706))
|
||||
- helpers: Upgrade n to version 9.2.0 ([#1727](https://github.com/yunohost/yunohost/pull/1727))
|
||||
- helpers: Update docker-image-extract to support more recent docker images ([#1733](https://github.com/yunohost/yunohost/pull/1733))
|
||||
- helpers: Add ynh_exec_and_print_stderr_only_if_error that only prints stderr when command fails ([#1723](https://github.com/yunohost/yunohost/pull/1723))
|
||||
- helpers: fix logrotate config file permission ([#1736](https://github.com/yunohost/yunohost/pull/1736))
|
||||
- helpers: make sure logfile exist when calling fail2ban helper ([#1737](https://github.com/yunohost/yunohost/pull/1737))
|
||||
- backup: Add post_app_restore hook ([#1708](https://github.com/yunohost/yunohost/pull/1708))
|
||||
- perf: speedup firewall reload ([#1734](https://github.com/yunohost/yunohost/pull/1734))
|
||||
- perf: prevent unecessary queries when building UserOption form ([#1738](https://github.com/yunohost/yunohost/pull/1738))
|
||||
- i18n: Translations updated for Basque, Catalan, French, Galician, Italian, Slovak, Spanish
|
||||
|
||||
Thanks to all contributors <3 ! (chri2, Chris Vogel, cristian amoyao, Éric Gaspar, Félix Piédallu, Jorge-vitrubio.net, José M, Jose Riha, ljf, mh4ckt3mh4ckt1c4s, OniriCorpe, Sebastian Gumprich, selfhoster1312, Tharyrok, Thomas, tituspijean, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 24 Nov 2023 22:01:50 +0100
|
||||
|
||||
yunohost (11.2.5) stable; urgency=low
|
||||
|
||||
- debian: fix conflict with openssl that is too harsh, openssl version on bullseye is now 1.1.1w, bookworm has 3.x (e8700bfe7)
|
||||
- dyndns: tweak dyndns subscribe/unsubscribe for dyndns recovery password integration in webadmin ([#1715](https://github.com/yunohost/yunohost/pull/1715))
|
||||
- helpers: ynh_setup_source: check and re-download a prefetched file that doesn't match the checksum (3dfab89c1)
|
||||
- helpers: ynh_setup_source: fix misleading example ([#1714](https://github.com/yunohost/yunohost/pull/1714))
|
||||
- helpers: php/apt: allow `phpX.Y` as sole dependency for `$phpversion=X.Y` ([#1722](https://github.com/yunohost/yunohost/pull/1722))
|
||||
- apps: fix typo in log statement ([#1709](https://github.com/yunohost/yunohost/pull/1709))
|
||||
- apps: allow system users to send mails from IPv6 localhost. ([#1710](https://github.com/yunohost/yunohost/pull/1710))
|
||||
- apps: add "support_purge" to app info for webadmin integration ([#1719](https://github.com/yunohost/yunohost/pull/1719))
|
||||
- diagnosis: be more flexible regarding accepted values for DMARC DNS records ([#1713](https://github.com/yunohost/yunohost/pull/1713))
|
||||
- dns: add home.arpa as special TLD (#1718) (bb097fedc)
|
||||
- i18n: Translations updated for Basque, French
|
||||
|
||||
Thanks to all contributors <3 ! (axolotle, Florian, Kayou, orhtej2, Pierre de La Morinerie, ppr, stanislas, tituspijean, xabirequejo)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 09 Oct 2023 23:16:13 +0200
|
||||
|
||||
yunohost (11.2.4) stable; urgency=low
|
||||
|
||||
- doc: Improve --help for 'yunohost app install' ([#1702](https://github.com/yunohost/yunohost/pull/1702))
|
||||
- helpers: add new --group option for ynh_add_fpm_config to customize the Group parameter (65d25710)
|
||||
- apps: allow to use jinja {% if foobar %} blocks in their notifications/doc pages (57699289)
|
||||
- apps: BACKUP_CORE_ONLY was not set for pre-upgrade safety backups, resulting in unecessarily large pre-upgrade backups (07daa687)
|
||||
- apps: Use the existing db_name setting for database provising to ease v1->v2 transition with specific db_name ([#1704](https://github.com/yunohost/yunohost/pull/1704))
|
||||
- configpanels/forms: more edge cases with some questions not implementing some methods/attributes (b0fe49ae)
|
||||
- diagnosis: reverse DNS check should be case-insensitive #2235 ([#1705](https://github.com/yunohost/yunohost/pull/1705))
|
||||
- i18n: Translations updated for Galician, Indonesian, Polish, Spanish, Turkish
|
||||
|
||||
Thanks to all contributors <3 ! (Grzegorz Cichocki, José M, Kuba Bazan, ljf (zamentur), massyas, Neko Nekowazarashi, selfhoster1312, Suleyman Harmandar, taco, Tagada)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 31 Aug 2023 17:30:21 +0200
|
||||
|
||||
yunohost (11.2.3) stable; urgency=low
|
||||
|
||||
- apps: fix another case of no attribute 'value' due to config panels/questions refactoring (4fda8ed49)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 22 Jul 2023 16:48:22 +0200
|
||||
|
||||
yunohost (11.2.2) stable; urgency=low
|
||||
|
||||
- domains: Gandi's `api_protocol` field should be a `select` type ([#1693](https://github.com/yunohost/yunohost/pull/1693))
|
||||
- configpanel: fix .value call for readonly-type options (e1ceb084)
|
||||
- i18n: Translations updated for French, Galician
|
||||
|
||||
Thanks to all contributors <3 ! (axolotle, José M, ppr, tituspijean)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 19 Jul 2023 02:35:28 +0200
|
||||
|
||||
yunohost (11.2.1) stable; urgency=low
|
||||
|
||||
- doc: fix resource doc generation .. not sure why this line that removed legit indent was there (ced222ea)
|
||||
- apps: hotfix for funky issue, apps getting named 'undefined' (781f924e)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 17 Jul 2023 21:13:54 +0200
|
||||
|
||||
yunohost (11.2) stable; urgency=low
|
||||
|
||||
- dyndns: add support for recovery passwords ([#1475](https://github.com/YunoHost/yunohost/pull/1475))
|
||||
- mail/apps: allow system users to auth on the mail stack and send emails ([#815](https://github.com/YunoHost/yunohost/pull/815))
|
||||
- nginx: fix OCSP stapling errors ([#1543](https://github.com/YunoHost/yunohost/pull/1534))
|
||||
- ssh: disable banner by default ([#1605](https://github.com/YunoHost/yunohost/pull/1605))
|
||||
- configpanels: another partial refactoring of config panels / questions, paving the way for Pydantic ([#1676](https://github.com/YunoHost/yunohost/pull/1676))
|
||||
- misc: rewrite the `yunopaste` tool ([#1667](https://github.com/YunoHost/yunohost/pull/1667))
|
||||
- apps: simplify the use of `ynh_add_fpm_config` ([#1684](https://github.com/YunoHost/yunohost/pull/1684))
|
||||
- apps: in ynh_systemd_action, check the actual timestamp when checking for timeout, because for some reason journalctl may take a ridiculous amount of time to run (f3eef43d)
|
||||
- i18n: Translations updated for German, Japanese
|
||||
|
||||
Thanks to all contributors <3 ! (André Théo LAURET, axolotle, Christian Wehrli, Éric Gaspar, ljf, motcha, theo-is-taken)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 17 Jul 2023 16:14:58 +0200
|
||||
|
||||
yunohost (11.1.22) stable; urgency=low
|
||||
|
||||
- security: replace $http_host by $host in nginx conf, cf https://github.com/yandex/gixy/blob/master/docs/en/plugins/hostspoofing.md / Credit to A.Wolski (3957b10e)
|
||||
- security: keep fail2ban rule when reloading firewall ([#1661](https://github.com/yunohost/yunohost/pull/1661))
|
||||
- regenconf: fix a stupid bug using chown instead of chmod ... (af93524c)
|
||||
- postinstall: crash early if the username already exists on the system (e87ee09b)
|
||||
- diagnosis: Support multiple TXT entries for TLD ([#1680](https://github.com/yunohost/yunohost/pull/1680))
|
||||
- apps: Support gitea's URL format ([#1683](https://github.com/yunohost/yunohost/pull/1683))
|
||||
- apps: fix a bug where YunoHost would complain that 'it needs X RAM but only Y left' with Y > X because some apps have a higher runtime RAM requirement than build time ... (4152cb0d)
|
||||
- apps: Enhance app_shell() : prevent from taking the lock + improve php context with a 'phpflags' setting ([#1681](https://github.com/yunohost/yunohost/pull/1681))
|
||||
- apps resources: Allow passing an actual list in the manifest.toml for the apt resource packages ([#1670](https://github.com/yunohost/yunohost/pull/1670))
|
||||
- apps resources: fix a bug where port automigration between v1->v2 wouldnt work (36a17dfd)
|
||||
- i18n: Translations updated for Basque, Galician, Japanese, Polish
|
||||
|
||||
Thanks to all contributors <3 ! (Félix Piédallu, Grzegorz Cichocki, José M, Kayou, motcha, Nicolas Palix, orhtej2, tituspijean, xabirequejo, Yann Autissier)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 10 Jul 2023 17:43:56 +0200
|
||||
|
||||
yunohost (11.1.21.4) stable; urgency=low
|
||||
|
||||
- regenconf: Get rid of previous tmp hack about /dev/null for people that went through the very first 11.1.21, because it's causing issue in unpriviledged LXC or similar context (8242cab7)
|
||||
- apps: don't attempt to del password key if it doesn't exist (29338f79)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 14 Jun 2023 15:48:33 +0200
|
||||
|
||||
yunohost (11.1.21.3) stable; urgency=low
|
||||
|
||||
- Fix again /var/www/.well-known/ynh-diagnosis/ perms which are too broad and could be exploited to serve malicious files x_x (84984ad8)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 12 Jun 2023 17:41:26 +0200
|
||||
|
||||
yunohost (11.1.21.2) stable; urgency=low
|
||||
|
||||
- Aleks loves xargs syntax >_> (313a1647)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 12 Jun 2023 00:25:44 +0200
|
||||
|
||||
yunohost (11.1.21.1) stable; urgency=low
|
||||
|
||||
- Fix stupid issue with code that changes /dev/null perms... (e6f134bc)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 12 Jun 2023 00:02:47 +0200
|
||||
|
||||
yunohost (11.1.21) stable; urgency=low
|
||||
|
||||
- users: more verbose logs for user_group_update operations ([#1668](https://github.com/yunohost/yunohost/pull/1668))
|
||||
- apps: fix auto-catalog update cron job which was broken because --apps doesnt exist anymore (1552944f)
|
||||
- apps: Add a 'yunohost app shell' command to open a shell into an app environment ([#1656](https://github.com/yunohost/yunohost/pull/1656))
|
||||
- security/regenconf: fix security issue where apps' system conf would be owned by the app, which can enable priviledge escalation (daf51e94)
|
||||
- security/regenconf: force systemd, nginx, php and fail2ban conf to be owned by root (e649c092)
|
||||
- security/nginx: use /var/www/.well-known folder for ynh diagnosis and acme challenge, because /tmp/ could be manipulated by user to serve maliciously crafted files (d42c9983)
|
||||
- i18n: Translations updated for French, Polish, Ukrainian
|
||||
|
||||
Thanks to all contributors <3 ! (Kay0u, Kuba Bazan, ppr, sudo, Tagada, tituspijean, Tymofii-Lytvynenko)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 11 Jun 2023 19:20:27 +0200
|
||||
|
||||
yunohost (11.1.20) stable; urgency=low
|
||||
|
||||
- appsv2: fix funky current_version not being defined when hydrating pre-upgrade notifications (8fa823b4)
|
||||
- helpers: using YNH_APP_ID instead of YNH_APP_INSTANCE_NAME during ynh_setup_source download, for more consistency and because tests was actually failing since a while because of this (e59a4f84)
|
||||
- helpers: improve error message for corrupt source in ynh_setup_source, it's more relevant to cite the source url rather than the downloaded output path (d698c4c3)
|
||||
- nginx: Update "worker" Content-Security-Policy header when in experimental security mode ([#1664](https://github.com/yunohost/yunohost/pull/1664))
|
||||
- i18n: Translations updated for French, Indonesian, Russian, Slovak
|
||||
|
||||
Thanks to all contributors <3 ! (axolotle, Éric Gaspar, Ilya, Jose Riha, Neko Nekowazarashi, Yann Autissier)
|
||||
|
||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 20 May 2023 18:57:26 +0200
|
||||
|
||||
yunohost (11.1.19) stable; urgency=low
|
||||
|
||||
- helpers: Upgrade n to version 9.1.0 ([#1646](https://github.com/yunohost/yunohost/pull/1646))
|
||||
|
@ -4812,4 +5302,3 @@ moulinette-yunohost (1.0~megusta1) megusta; urgency=low
|
|||
* Init
|
||||
|
||||
-- Adrien Beudin <beudbeud@yunohost.org> Thu, 15 May 2014 13:16:03 +0200
|
||||
|
||||
|
|
27
debian/control
vendored
27
debian/control
vendored
|
@ -2,34 +2,34 @@ 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
|
||||
Build-Depends: debhelper (>=9), debhelper-compat (= 13), dh-python, python3-all (>= 3.11), python3-yaml, python3-jinja2 (>= 3.0)
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: https://yunohost.org/
|
||||
|
||||
Package: yunohost
|
||||
Essential: yes
|
||||
Architecture: all
|
||||
Depends: ${python3:Depends}, ${misc:Depends}
|
||||
, moulinette (>= 11.1), ssowat (>= 11.1)
|
||||
Depends: python3-all (>= 3.11),
|
||||
, moulinette (>= 12.0), ssowat (>= 12.0),
|
||||
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
||||
, python3-miniupnpc, python3-dbus, python3-jinja2
|
||||
, python3-miniupnpc, python3-dbus, python3-jinja2 (>= 3.0)
|
||||
, python3-toml, python3-packaging, python3-publicsuffix2
|
||||
, python3-ldap, python3-zeroconf (>=0.47), python3-lexicon,
|
||||
, python-is-python3
|
||||
, 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)
|
||||
, apt, apt-transport-https, apt-utils, dirmngr
|
||||
, apt, apt-transport-https, apt-utils, aptitude, dirmngr
|
||||
, openssh-server, iptables, fail2ban, bind9-dnsutils
|
||||
, openssl, ca-certificates, netcat-openbsd, iproute2
|
||||
, slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd
|
||||
, dnsmasq, resolvconf, libnss-myhostname
|
||||
, postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre
|
||||
, dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam
|
||||
, rspamd, opendkim-tools, postsrsd, procmail, mailutils
|
||||
, redis-server
|
||||
, opendkim-tools, opendkim, postsrsd, procmail, mailutils
|
||||
, acl
|
||||
, git, curl, wget, cron, unzip, jq, bc, at, procps
|
||||
, lsb-release, haveged, fake-hwclock, equivs, lsof, whois
|
||||
Recommends: yunohost-admin
|
||||
, git, curl, wget, cron, unzip, jq, bc, at, procps, j2cli
|
||||
, lsb-release, haveged, fake-hwclock, lsof, whois
|
||||
Recommends: yunohost-admin, yunohost-portal (>= 12.0)
|
||||
, ntp, inetutils-ping | iputils-ping
|
||||
, bash-completion, rsyslog
|
||||
, unattended-upgrades
|
||||
|
@ -37,11 +37,12 @@ Recommends: yunohost-admin
|
|||
Conflicts: iptables-persistent
|
||||
, apache2
|
||||
, bind9
|
||||
, openresolv
|
||||
, systemd-resolved
|
||||
, nginx-extras (>= 1.23)
|
||||
, openssl (>= 3.1)
|
||||
, slapd (>= 2.6)
|
||||
, dovecot-core (>= 1:2.4)
|
||||
, redis-server (>= 5:7.1)
|
||||
, fail2ban (>= 1.1)
|
||||
, iptables (>= 1.8.10)
|
||||
Description: manageable and configured self-hosting server
|
||||
|
|
3
debian/install
vendored
3
debian/install
vendored
|
@ -1,10 +1,9 @@
|
|||
bin/* /usr/bin/
|
||||
share/* /usr/share/yunohost/
|
||||
hooks/* /usr/share/yunohost/hooks/
|
||||
helpers/* /usr/share/yunohost/helpers.d/
|
||||
helpers/* /usr/share/yunohost/
|
||||
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/
|
||||
|
|
6
debian/postinst
vendored
6
debian/postinst
vendored
|
@ -4,6 +4,10 @@ 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 ...
|
||||
|
@ -33,6 +37,8 @@ do_configure() {
|
|||
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
|
||||
|
|
|
@ -8,6 +8,7 @@ adds `--help` at the end if one presses [tab] again.
|
|||
|
||||
author: Christophe Vuillot
|
||||
"""
|
||||
|
||||
import os
|
||||
import yaml
|
||||
|
||||
|
|
181
doc/generate_configpanel_and_formoptions_doc.py
Normal file
181
doc/generate_configpanel_and_formoptions_doc.py
Normal file
|
@ -0,0 +1,181 @@
|
|||
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()
|
|
@ -1,10 +1,55 @@
|
|||
#!/usr/env/python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import glob
|
||||
import datetime
|
||||
import subprocess
|
||||
|
||||
tree = {
|
||||
"sources": {
|
||||
"title": "Sources",
|
||||
"notes": "This is coupled to the 'sources' resource in the manifest.toml",
|
||||
"subsections": ["sources"],
|
||||
},
|
||||
"tech": {
|
||||
"title": "App technologies",
|
||||
"notes": "These allow to install specific version of the technology required to run some apps",
|
||||
"subsections": ["nodejs", "ruby", "go", "composer"],
|
||||
},
|
||||
"db": {
|
||||
"title": "Databases",
|
||||
"notes": "This is coupled to the 'database' resource in the manifest.toml - at least for mysql/postgresql. Mongodb/redis may have better integration in the future.",
|
||||
"subsections": ["mysql", "postgresql", "mongodb", "redis"],
|
||||
},
|
||||
"conf": {
|
||||
"title": "Configurations / templating",
|
||||
"subsections": [
|
||||
"templating",
|
||||
"nginx",
|
||||
"php",
|
||||
"systemd",
|
||||
"fail2ban",
|
||||
"logrotate",
|
||||
],
|
||||
},
|
||||
"misc": {
|
||||
"title": "Misc tools",
|
||||
"subsections": [
|
||||
"utils",
|
||||
"setting",
|
||||
"string",
|
||||
"backup",
|
||||
"logging",
|
||||
"multimedia",
|
||||
],
|
||||
},
|
||||
"meh": {
|
||||
"title": "Deprecated or handled by the core / app resources since v2",
|
||||
"subsections": ["permission", "apt", "systemuser"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def get_current_commit():
|
||||
p = subprocess.Popen(
|
||||
|
@ -19,14 +64,7 @@ def get_current_commit():
|
|||
return current_commit
|
||||
|
||||
|
||||
def render(helpers):
|
||||
current_commit = get_current_commit()
|
||||
|
||||
data = {
|
||||
"helpers": helpers,
|
||||
"date": datetime.datetime.now().strftime("%d/%m/%Y"),
|
||||
"version": open("../debian/changelog").readlines()[0].split()[1].strip("()"),
|
||||
}
|
||||
def render(tree, helpers_version):
|
||||
|
||||
from jinja2 import Template
|
||||
from ansi2html import Ansi2HTMLConverter
|
||||
|
@ -42,12 +80,15 @@ def render(helpers):
|
|||
t = Template(template)
|
||||
t.globals["now"] = datetime.datetime.utcnow
|
||||
result = t.render(
|
||||
current_commit=current_commit,
|
||||
data=data,
|
||||
tree=tree,
|
||||
date=datetime.datetime.now().strftime("%d/%m/%Y"),
|
||||
version=open("../debian/changelog").readlines()[0].split()[1].strip("()"),
|
||||
helpers_version=helpers_version,
|
||||
current_commit=get_current_commit(),
|
||||
convert=shell_to_html,
|
||||
shell_css=shell_css,
|
||||
)
|
||||
open("helpers.md", "w").write(result)
|
||||
open(f"helpers.v{helpers_version}.md", "w").write(result)
|
||||
|
||||
|
||||
##############################################################################
|
||||
|
@ -87,7 +128,7 @@ class Parser:
|
|||
# We're still in a comment bloc
|
||||
assert line.startswith("# ") or line == "#", malformed_error(i)
|
||||
current_block["comments"].append(line[2:])
|
||||
elif line.strip() == "":
|
||||
elif line.strip() == "" or line.startswith("_ynh"):
|
||||
# Well eh that was not an actual helper definition ... start over ?
|
||||
current_reading = "void"
|
||||
current_block = {
|
||||
|
@ -119,7 +160,14 @@ class Parser:
|
|||
|
||||
# Then we keep this bloc and start a new one
|
||||
# (we ignore helpers containing [internal] ...)
|
||||
if "[internal]" not in current_block["comments"]:
|
||||
if (
|
||||
"[packagingv1]" not in current_block["comments"]
|
||||
and not any(
|
||||
line.startswith("[internal]")
|
||||
for line in current_block["comments"]
|
||||
)
|
||||
and not current_block["name"].startswith("_")
|
||||
):
|
||||
self.blocks.append(current_block)
|
||||
current_block = {
|
||||
"name": None,
|
||||
|
@ -209,23 +257,27 @@ def malformed_error(line_number):
|
|||
|
||||
|
||||
def main():
|
||||
helper_files = sorted(glob.glob("../helpers/*"))
|
||||
helpers = []
|
||||
|
||||
for helper_file in helper_files:
|
||||
if not os.path.isfile(helper_file):
|
||||
continue
|
||||
if len(sys.argv) == 1:
|
||||
print("This script needs the helper version (1, 2, 2.1) as an argument")
|
||||
sys.exit(1)
|
||||
|
||||
category_name = os.path.basename(helper_file)
|
||||
print("Parsing %s ..." % category_name)
|
||||
version = sys.argv[1]
|
||||
|
||||
for section in tree.values():
|
||||
section["helpers"] = {}
|
||||
for subsection in section["subsections"]:
|
||||
print(f"Parsing {subsection} ...")
|
||||
helper_file = f"../helpers/helpers.v{version}.d/{subsection}"
|
||||
assert os.path.isfile(helper_file), f"Uhoh, {file} doesn't exists?"
|
||||
p = Parser(helper_file)
|
||||
p.parse_blocks()
|
||||
for b in p.blocks:
|
||||
p.parse_block(b)
|
||||
|
||||
helpers.append((category_name, p.blocks))
|
||||
section["helpers"][subsection] = p.blocks
|
||||
|
||||
render(helpers)
|
||||
render(tree, version)
|
||||
|
||||
|
||||
main()
|
||||
|
|
4
doc/generate_json_schema.py
Normal file
4
doc/generate_json_schema.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from yunohost.utils.configpanel import ConfigPanelModel
|
||||
|
||||
|
||||
print(ConfigPanelModel.schema_json(indent=2))
|
|
@ -62,9 +62,7 @@ for c in ResourceClasses:
|
|||
|
||||
|
||||
for resource_id, doc in sorted(ResourceDocString.items()):
|
||||
doc = doc.replace("\n ", "\n")
|
||||
|
||||
print("----------------")
|
||||
print("---")
|
||||
print("")
|
||||
print(f"## {resource_id.replace('_', ' ').title()}")
|
||||
print("")
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
---
|
||||
title: App helpers
|
||||
title: App helpers (v{{ helpers_version }})
|
||||
template: docs
|
||||
taxonomy:
|
||||
category: docs
|
||||
routes:
|
||||
default: '/packaging_apps_helpers'
|
||||
default: '/packaging_apps_helpers{% if helpers_version not in ["1", "2"] %}_v{{ helpers_version }}{% endif %}'
|
||||
---
|
||||
|
||||
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}})
|
||||
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{date}} (YunoHost version {{version}})
|
||||
|
||||
{% for category, helpers in data.helpers %}
|
||||
## {{ category.upper() }}
|
||||
{% for h in helpers %}
|
||||
|
||||
{% for section_id, section in tree.items() %}
|
||||
## {{ section["title"].title() }}
|
||||
|
||||
{% if section['notes'] %}<p>{{ section['notes'] }}</p>{% endif %}
|
||||
|
||||
{% for subsection, helpers in section["helpers"].items() %}
|
||||
|
||||
### {{ subsection.upper() }}
|
||||
{% for h in helpers %}
|
||||
#### {{ h.name }}
|
||||
|
||||
[details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"]
|
||||
|
||||
**Usage**: `{{ h.usage }}`
|
||||
|
@ -48,12 +56,12 @@ Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{
|
|||
{%- endif %}
|
||||
{%- if h.details %}
|
||||
|
||||
**Details**:<br/>
|
||||
**Details**:
|
||||
{{ h.details }}
|
||||
{%- endif %}
|
||||
|
||||
[Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/helpers/{{ category }}#L{{ h.line + 1 }})
|
||||
[Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/helpers/helpers.v{{ helpers_version if helpers_version != "2" else "1" }}.d/{{ subsection }}#L{{ h.line + 1 }})
|
||||
[/details]
|
||||
----------------
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
---
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
|
113
helpers/apps
113
helpers/apps
|
@ -1,113 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install others YunoHost apps
|
||||
#
|
||||
# usage: ynh_install_apps --apps="appfoo?domain=domain.foo&path=/foo appbar?domain=domain.bar&path=/bar&admin=USER&language=fr&is_public=1&pass?word=pass&port=666"
|
||||
# | arg: -a, --apps= - apps to install
|
||||
#
|
||||
# Requires YunoHost version *.*.* or higher.
|
||||
ynh_install_apps() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=a
|
||||
local -A args_array=([a]=apps=)
|
||||
local apps
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Split the list of apps in an array
|
||||
local apps_list=($(echo $apps | tr " " "\n"))
|
||||
local apps_dependencies=""
|
||||
|
||||
# For each app
|
||||
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"
|
||||
|
||||
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
|
||||
# Retrieve the arguments of the app (part after ?)
|
||||
local one_argument=""
|
||||
if [[ "$one_app_and_its_args" == *"?"* ]]; then
|
||||
one_argument=$(cut -d "?" -f2- <<< "$one_app_and_its_args")
|
||||
one_argument="--args $one_argument"
|
||||
fi
|
||||
|
||||
# Install the app with its arguments
|
||||
yunohost app install $one_app $one_argument
|
||||
else
|
||||
# Upgrade the app
|
||||
yunohost app upgrade $one_app
|
||||
fi
|
||||
|
||||
if [ ! -z "$apps_dependencies" ]
|
||||
then
|
||||
apps_dependencies="$apps_dependencies, $one_app"
|
||||
else
|
||||
apps_dependencies="$one_app"
|
||||
fi
|
||||
done
|
||||
|
||||
ynh_app_setting_set --app=$app --key=apps_dependencies --value="$apps_dependencies"
|
||||
}
|
||||
|
||||
# Remove other YunoHost apps
|
||||
#
|
||||
# Other YunoHost apps will be removed only if no other apps need them.
|
||||
#
|
||||
# usage: ynh_remove_apps
|
||||
#
|
||||
# Requires YunoHost version *.*.* or higher.
|
||||
ynh_remove_apps() {
|
||||
# Retrieve the apps dependencies of the app
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
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
|
||||
if [[ $one_installed_app_dependency == $one_app ]]; then
|
||||
required_by="$required_by $one_installed_app"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# If $one_app is no more required
|
||||
if [[ -z "$required_by" ]]
|
||||
then
|
||||
# Remove $one_app
|
||||
ynh_print_info --message="Removing of $one_app"
|
||||
yunohost app remove $one_app --purge
|
||||
else
|
||||
ynh_print_info --message="$one_app was not removed because it's still required by${required_by}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
25
helpers/helpers
Normal file
25
helpers/helpers
Normal file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# Entrypoint for the helpers scripts
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
# Helpers version can be specified via an environment variable or default to 1.
|
||||
YNH_HELPERS_VERSION=${YNH_HELPERS_VERSION:-1}
|
||||
|
||||
# This is a trick to later only restore set -x if it was set when calling this script
|
||||
readonly XTRACE_ENABLE=$(set +o | grep xtrace)
|
||||
set +x
|
||||
|
||||
YNH_HELPERS_DIR="$SCRIPT_DIR/helpers.v${YNH_HELPERS_VERSION}.d"
|
||||
case "$YNH_HELPERS_VERSION" in
|
||||
"1" | "2" | "2.1")
|
||||
readarray -t HELPERS < <(find -L "$YNH_HELPERS_DIR" -mindepth 1 -maxdepth 1 -type f)
|
||||
for helper in "${HELPERS[@]}"; do
|
||||
[ -r "$helper" ] && source "$helper"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "Helpers are not available in version '$YNH_HELPERS_VERSION'." >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
eval "$XTRACE_ENABLE"
|
215
helpers/helpers.v1.d/apps
Normal file
215
helpers/helpers.v1.d/apps
Normal file
|
@ -0,0 +1,215 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install others YunoHost apps
|
||||
#
|
||||
# usage: ynh_install_apps --apps="appfoo?domain=domain.foo&path=/foo appbar?domain=domain.bar&path=/bar&admin=USER&language=fr&is_public=1&pass?word=pass&port=666"
|
||||
# | arg: -a, --apps= - apps to install
|
||||
#
|
||||
# Requires YunoHost version *.*.* or higher.
|
||||
ynh_install_apps() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=a
|
||||
local -A args_array=([a]=apps=)
|
||||
local apps
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Split the list of apps in an array
|
||||
local apps_list=($(echo $apps | tr " " "\n"))
|
||||
local apps_dependencies=""
|
||||
|
||||
# For each app
|
||||
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"
|
||||
|
||||
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
|
||||
# Retrieve the arguments of the app (part after ?)
|
||||
local one_argument=""
|
||||
if [[ "$one_app_and_its_args" == *"?"* ]]; then
|
||||
one_argument=$(cut -d "?" -f2- <<< "$one_app_and_its_args")
|
||||
one_argument="--args $one_argument"
|
||||
fi
|
||||
|
||||
# Install the app with its arguments
|
||||
yunohost app install $one_app $one_argument
|
||||
else
|
||||
# Upgrade the app
|
||||
yunohost app upgrade $one_app
|
||||
fi
|
||||
|
||||
if [ ! -z "$apps_dependencies" ]
|
||||
then
|
||||
apps_dependencies="$apps_dependencies, $one_app"
|
||||
else
|
||||
apps_dependencies="$one_app"
|
||||
fi
|
||||
done
|
||||
|
||||
ynh_app_setting_set --app=$app --key=apps_dependencies --value="$apps_dependencies"
|
||||
}
|
||||
|
||||
# Remove other YunoHost apps
|
||||
#
|
||||
# Other YunoHost apps will be removed only if no other apps need them.
|
||||
#
|
||||
# usage: ynh_remove_apps
|
||||
#
|
||||
# Requires YunoHost version *.*.* or higher.
|
||||
ynh_remove_apps() {
|
||||
# Retrieve the apps dependencies of the app
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
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
|
||||
if [[ $one_installed_app_dependency == $one_app ]]; then
|
||||
required_by="$required_by $one_installed_app"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# If $one_app is no more required
|
||||
if [[ -z "$required_by" ]]
|
||||
then
|
||||
# Remove $one_app
|
||||
ynh_print_info --message="Removing of $one_app"
|
||||
yunohost app remove $one_app --purge
|
||||
else
|
||||
ynh_print_info --message="$one_app was not removed because it's still required by${required_by}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Spawn a Bash shell with the app environment loaded
|
||||
#
|
||||
# usage: ynh_spawn_app_shell --app="app"
|
||||
# | arg: -a, --app= - the app ID
|
||||
#
|
||||
# examples:
|
||||
# ynh_spawn_app_shell --app="APP" <<< 'echo "$USER"'
|
||||
# ynh_spawn_app_shell --app="APP" < /tmp/some_script.bash
|
||||
#
|
||||
# Requires YunoHost version 11.0.* or higher, and that the app relies on packaging v2 or higher.
|
||||
# The spawned shell will have environment variables loaded and environment files sourced
|
||||
# from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting).
|
||||
# If the app relies on a specific PHP version, then `php` will be aliased that version. The PHP command will also be appended with the `phpflags` settings.
|
||||
ynh_spawn_app_shell() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=a
|
||||
local -A args_array=([a]=app=)
|
||||
local app
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Force Bash to be used to run this helper
|
||||
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
|
||||
ynh_print_err --message="$app is not in the apps list"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the app has its own user
|
||||
if ! id -u "$app" &>/dev/null; then
|
||||
ynh_print_err --message="There is no \"$app\" system user"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
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;
|
||||
|
||||
# Export HOME variable
|
||||
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;
|
||||
|
||||
# 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
|
||||
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
|
||||
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
|
||||
set -a
|
||||
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
|
||||
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
|
||||
set -a
|
||||
source $install_dir/venv/bin/activate
|
||||
set +a
|
||||
fi
|
||||
|
||||
# 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;
|
||||
cd $env_dir
|
||||
|
||||
# Spawn the app shell
|
||||
su -s /bin/bash $app
|
||||
}
|
|
@ -58,7 +58,6 @@ ynh_package_is_installed() {
|
|||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
ynh_wait_dpkg_free
|
||||
dpkg-query --show --showformat='${Status}' "$package" 2>/dev/null \
|
||||
| grep --count "ok installed" &>/dev/null
|
||||
}
|
||||
|
@ -67,6 +66,8 @@ ynh_package_is_installed() {
|
|||
#
|
||||
# example: version=$(ynh_package_version --package=yunohost)
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_version --package=name
|
||||
# | arg: -p, --package= - the package name to get version
|
||||
# | ret: the version or an empty string
|
||||
|
@ -101,6 +102,8 @@ ynh_apt() {
|
|||
|
||||
# Update package index files
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_update
|
||||
#
|
||||
# Requires YunoHost version 2.2.4 or higher.
|
||||
|
@ -110,6 +113,8 @@ ynh_package_update() {
|
|||
|
||||
# Install package(s)
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_install name [name [...]]
|
||||
# | arg: name - the package name to install
|
||||
#
|
||||
|
@ -121,6 +126,8 @@ ynh_package_install() {
|
|||
|
||||
# Remove package(s)
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_remove name [name [...]]
|
||||
# | arg: name - the package name to remove
|
||||
#
|
||||
|
@ -131,6 +138,8 @@ ynh_package_remove() {
|
|||
|
||||
# Remove package(s) and their uneeded dependencies
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_autoremove name [name [...]]
|
||||
# | arg: name - the package name to remove
|
||||
#
|
||||
|
@ -141,6 +150,8 @@ ynh_package_autoremove() {
|
|||
|
||||
# Purge package(s) and their uneeded dependencies
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_package_autopurge name [name [...]]
|
||||
# | arg: name - the package name to autoremove and purge
|
||||
#
|
||||
|
@ -175,21 +186,21 @@ ynh_package_install_from_equivs() {
|
|||
|
||||
# Build and install the package
|
||||
local TMPDIR=$(mktemp --directory)
|
||||
|
||||
# Make sure to delete the legacy compat file
|
||||
# It's now handle somewhat magically through the control file
|
||||
rm -f /usr/share/equivs/template/debian/compat
|
||||
mkdir -p ${TMPDIR}/${pkgname}/DEBIAN/
|
||||
# For some reason, dpkg-deb insists for folder perm to be 755 and sometimes it's 777 o_O?
|
||||
chmod -R 755 ${TMPDIR}/${pkgname}
|
||||
|
||||
# Note that the cd executes into a sub shell
|
||||
# Create a fake deb package with equivs-build and the given control file
|
||||
# Install the fake package without its dependencies with dpkg
|
||||
# Install missing dependencies with ynh_package_install
|
||||
ynh_wait_dpkg_free
|
||||
cp "$controlfile" "${TMPDIR}/control"
|
||||
cp "$controlfile" "${TMPDIR}/${pkgname}/DEBIAN/control"
|
||||
(
|
||||
cd "$TMPDIR"
|
||||
LC_ALL=C equivs-build ./control 2>&1
|
||||
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log
|
||||
# Install the fake package without its dependencies with dpkg --force-depends
|
||||
LC_ALL=C dpkg-deb --build ${pkgname} ${pkgname}.deb > ./dpkg_log 2>&1 || { cat ./dpkg_log; false; }
|
||||
LC_ALL=C dpkg --force-depends --install "./${pkgname}.deb" 2>&1 | tee ./dpkg_log
|
||||
)
|
||||
|
||||
ynh_package_install --fix-broken \
|
||||
|
@ -250,7 +261,7 @@ ynh_install_app_dependencies() {
|
|||
# Check for specific php dependencies which requires sury
|
||||
# This grep will for example return "7.4" if dependencies is "foo bar php7.4-pwet php-gni"
|
||||
# The (?<=php) syntax corresponds to lookbehind ;)
|
||||
local specific_php_version=$(echo $dependencies | grep -oP '(?<=php)[0-9.]+(?=-|\>)' | sort -u)
|
||||
local specific_php_version=$(echo $dependencies | grep -oP '(?<=php)[0-9.]+(?=-|\>|)' | sort -u)
|
||||
|
||||
if [[ -n "$specific_php_version" ]]
|
||||
then
|
||||
|
@ -312,6 +323,7 @@ Package: ${dep_app}-ynh-deps
|
|||
Version: ${version}
|
||||
Depends: ${dependencies}
|
||||
Architecture: all
|
||||
Maintainer: root@localhost
|
||||
Description: Fake package for ${app} (YunoHost app) dependencies
|
||||
This meta-package is only responsible of installing its dependencies.
|
||||
EOF
|
||||
|
@ -331,6 +343,8 @@ EOF
|
|||
|
||||
# Add dependencies to install with ynh_install_app_dependencies
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
||||
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
||||
#
|
||||
|
@ -418,7 +432,7 @@ ynh_install_extra_app_dependencies() {
|
|||
[ -z "$apps_auto_installed" ] || apt-mark auto $apps_auto_installed
|
||||
|
||||
# Remove this extra repository after packages are installed
|
||||
ynh_remove_extra_repo --name=$app
|
||||
ynh_remove_extra_repo --name=$name
|
||||
}
|
||||
|
||||
# Add an extra repository correctly, pin it and get the key.
|
||||
|
@ -457,21 +471,29 @@ ynh_install_extra_repo() {
|
|||
wget_append="tee"
|
||||
fi
|
||||
|
||||
# Split the repository into uri, suite and components.
|
||||
if [[ "$key" == "trusted=yes" ]]; then
|
||||
trusted="--trusted"
|
||||
else
|
||||
trusted=""
|
||||
fi
|
||||
|
||||
IFS=', ' read -r -a repo_parts <<< "$repo"
|
||||
index=0
|
||||
|
||||
# Remove "deb " at the beginning of the repo.
|
||||
repo="${repo#deb }"
|
||||
|
||||
# Get the uri
|
||||
local uri="$(echo "$repo" | awk '{ print $1 }')"
|
||||
|
||||
# Get the suite
|
||||
local suite="$(echo "$repo" | awk '{ print $2 }')"
|
||||
if [[ "${repo_parts[0]}" == "deb" ]]; then
|
||||
index=1
|
||||
fi
|
||||
uri="${repo_parts[$index]}" ; index=$((index+1))
|
||||
suite="${repo_parts[$index]}" ; index=$((index+1))
|
||||
|
||||
# Get the components
|
||||
local component="${repo##$uri $suite }"
|
||||
if (( "${#repo_parts[@]}" > 0 )); then
|
||||
component="${repo_parts[*]:$index}"
|
||||
fi
|
||||
|
||||
# Add the repository into sources.list.d
|
||||
ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append
|
||||
ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append $trusted
|
||||
|
||||
# Pin the new repo with the default priority, so it won't be used for upgrades.
|
||||
# Build $pin from the uri without http and any sub path
|
||||
|
@ -484,7 +506,7 @@ ynh_install_extra_repo() {
|
|||
ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append
|
||||
|
||||
# Get the public key for the repo
|
||||
if [ -n "$key" ]; then
|
||||
if [ -n "$key" ] && [[ "$key" != "trusted=yes" ]]; then
|
||||
mkdir --parents "/etc/apt/trusted.gpg.d"
|
||||
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
||||
wget --timeout 900 --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg >/dev/null
|
||||
|
@ -537,6 +559,7 @@ ynh_remove_extra_repo() {
|
|||
# | arg: -c, --component= - Component of the repository.
|
||||
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||
# | arg: -a, --append - Do not overwrite existing files.
|
||||
# | arg: -t, --trusted - Add trusted=yes to the repository (not recommended)
|
||||
#
|
||||
# Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable
|
||||
# uri suite component
|
||||
|
@ -545,27 +568,34 @@ ynh_remove_extra_repo() {
|
|||
# Requires YunoHost version 3.8.1 or higher.
|
||||
ynh_add_repo() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=uscna
|
||||
local -A args_array=([u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append)
|
||||
local legacy_args=uscnat
|
||||
local -A args_array=([u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append [t]=trusted)
|
||||
local uri
|
||||
local suite
|
||||
local component
|
||||
local name
|
||||
local append
|
||||
local trusted
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
name="${name:-$app}"
|
||||
append=${append:-0}
|
||||
trusted=${trusted:-0}
|
||||
|
||||
if [ $append -eq 1 ]; then
|
||||
append="tee --append"
|
||||
else
|
||||
append="tee"
|
||||
fi
|
||||
if [[ "$trusted" -eq 1 ]]; then
|
||||
trust="[trusted=yes]"
|
||||
else
|
||||
trust=""
|
||||
fi
|
||||
|
||||
mkdir --parents "/etc/apt/sources.list.d"
|
||||
# Add the new repo in sources.list.d
|
||||
echo "deb $uri $suite $component" \
|
||||
echo "deb $trust $uri $suite $component" \
|
||||
| $append "/etc/apt/sources.list.d/$name.list"
|
||||
}
|
||||
|
|
@ -417,6 +417,8 @@ ynh_backup_archive_exists() {
|
|||
|
||||
# Make a backup in case of failed upgrade
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_backup_before_upgrade
|
||||
#
|
||||
# Usage in a package script:
|
||||
|
@ -465,6 +467,8 @@ ynh_backup_before_upgrade() {
|
|||
|
||||
# Restore a previous backup if the upgrade process failed
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_restore_upgradebackup
|
||||
#
|
||||
# Usage in a package script:
|
82
helpers/helpers.v1.d/composer
Normal file
82
helpers/helpers.v1.d/composer
Normal file
|
@ -0,0 +1,82 @@
|
|||
#!/bin/bash
|
||||
|
||||
readonly YNH_DEFAULT_COMPOSER_VERSION=1.10.17
|
||||
# Declare the actual composer version to use.
|
||||
# A packager willing to use another version of composer can override the variable into its _common.sh.
|
||||
YNH_COMPOSER_VERSION=${YNH_COMPOSER_VERSION:-$YNH_DEFAULT_COMPOSER_VERSION}
|
||||
|
||||
# Execute a command with Composer
|
||||
#
|
||||
# usage: ynh_composer_exec [--phpversion=phpversion] [--workdir=$install_dir] --commands="commands"
|
||||
# | arg: -v, --phpversion - PHP version to use with composer
|
||||
# | arg: -w, --workdir - The directory from where the command will be executed. Default $install_dir or $final_path
|
||||
# | arg: -c, --commands - Commands to execute.
|
||||
#
|
||||
# Requires YunoHost version 4.2 or higher.
|
||||
ynh_composer_exec() {
|
||||
local _globalphpversion=${phpversion-:}
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=vwc
|
||||
declare -Ar args_array=([v]=phpversion= [w]=workdir= [c]=commands=)
|
||||
local phpversion
|
||||
local workdir
|
||||
local commands
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
workdir="${workdir:-${install_dir:-$final_path}}"
|
||||
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||
else
|
||||
phpversion="${phpversion:-$_globalphpversion}"
|
||||
fi
|
||||
|
||||
COMPOSER_HOME="$workdir/.composer" COMPOSER_MEMORY_LIMIT=-1 \
|
||||
php${phpversion} "$workdir/composer.phar" $commands \
|
||||
-d "$workdir" --no-interaction --no-ansi 2>&1
|
||||
}
|
||||
|
||||
# Install and initialize Composer in the given directory
|
||||
#
|
||||
# usage: ynh_install_composer [--phpversion=phpversion] [--workdir=$install_dir] [--install_args="--optimize-autoloader"] [--composerversion=composerversion]
|
||||
# | arg: -v, --phpversion - PHP version to use with composer
|
||||
# | arg: -w, --workdir - The directory from where the command will be executed. Default $install_dir.
|
||||
# | arg: -a, --install_args - Additional arguments provided to the composer install. Argument --no-dev already include
|
||||
# | arg: -c, --composerversion - Composer version to install
|
||||
#
|
||||
# Requires YunoHost version 4.2 or higher.
|
||||
ynh_install_composer() {
|
||||
local _globalphpversion=${phpversion-:}
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=vwac
|
||||
declare -Ar args_array=([v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
|
||||
local phpversion
|
||||
local workdir
|
||||
local install_args
|
||||
local composerversion
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
workdir="${workdir:-$final_path}"
|
||||
else
|
||||
workdir="${workdir:-$install_dir}"
|
||||
fi
|
||||
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||
else
|
||||
phpversion="${phpversion:-$_globalphpversion}"
|
||||
fi
|
||||
|
||||
install_args="${install_args:-}"
|
||||
composerversion="${composerversion:-$YNH_COMPOSER_VERSION}"
|
||||
|
||||
curl -sS https://getcomposer.org/installer \
|
||||
| COMPOSER_HOME="$workdir/.composer" \
|
||||
php${phpversion} -- --quiet --install-dir="$workdir" --version=$composerversion \
|
||||
|| ynh_die --message="Unable to install Composer."
|
||||
|
||||
# install dependencies
|
||||
ynh_composer_exec --phpversion="${phpversion}" --workdir="$workdir" --commands="install --no-dev $install_args" \
|
||||
|| ynh_die --message="Unable to install core dependencies with Composer."
|
||||
}
|
|
@ -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 "$(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)" 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 $(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/) 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 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
|
||||
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="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
|
||||
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="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
|
||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||
echo "${!short_setting}" >"$bind_file"
|
||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||
|
@ -108,12 +108,12 @@ _ynh_app_config_apply_one() {
|
|||
else
|
||||
local bind_after=""
|
||||
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||
bind_key_=${bind_key_:-$short_setting}
|
||||
if [[ "$bind_key_" == *">"* ]]; then
|
||||
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/)"
|
||||
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/)"
|
||||
|
||||
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}"
|
||||
|
@ -139,21 +139,49 @@ 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
|
||||
print(';'.join([
|
||||
|
||||
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'),
|
||||
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
|
||||
bind
|
||||
]))
|
||||
EOL
|
||||
)
|
||||
for line in $lines; do
|
||||
# Split line into short_setting, type and bind
|
||||
IFS=';' read short_setting type bind <<<"$line"
|
||||
IFS='|' read short_setting type bind <<<"$line"
|
||||
binds[${short_setting}]="$bind"
|
||||
types[${short_setting}]="$type"
|
||||
file_hash[${short_setting}]=""
|
||||
|
@ -176,8 +204,7 @@ _ynh_app_config_show() {
|
|||
ynh_return "${short_setting}:"
|
||||
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
||||
else
|
||||
ynh_return "${short_setting}: "'"'"$(echo "${old[$short_setting]}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\n\n/g')"'"'
|
||||
|
||||
ynh_return "${short_setting}: '$(echo "${old[$short_setting]}" | sed "s/'/''/g" | sed ':a;N;$!ba;s/\n/\n\n/g')'"
|
||||
fi
|
||||
fi
|
||||
done
|
|
@ -8,8 +8,6 @@
|
|||
# | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
|
||||
# | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# usage 2: ynh_add_fail2ban_config --use_template
|
||||
# | arg: -t, --use_template - Use this helper in template mode
|
||||
#
|
||||
|
@ -42,9 +40,7 @@
|
|||
# ignoreregex =
|
||||
# ```
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Note about the "failregex" option:
|
||||
# ##### Note about the "failregex" option:
|
||||
#
|
||||
# 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
|
||||
|
@ -53,8 +49,6 @@
|
|||
# You can find some more explainations about how to make a regex here :
|
||||
# https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters
|
||||
#
|
||||
# Note that the logfile need to exist before to call this helper !!
|
||||
#
|
||||
# To validate your regex you can test with this command:
|
||||
# ```
|
||||
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
|
||||
|
@ -76,7 +70,7 @@ ynh_add_fail2ban_config() {
|
|||
ports=${ports:-http,https}
|
||||
use_template="${use_template:-0}"
|
||||
|
||||
if [ $use_template -ne 1 ]; then
|
||||
if [ "$use_template" -ne 1 ]; then
|
||||
# Usage 1, no template. Build a config file from scratch.
|
||||
test -n "$logpath" || ynh_die --message="ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
|
||||
test -n "$failregex" || ynh_die --message="ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
|
||||
|
@ -88,7 +82,7 @@ port = __PORTS__
|
|||
filter = __APP__
|
||||
logpath = __LOGPATH__
|
||||
maxretry = __MAX_RETRY__
|
||||
" >$YNH_APP_BASEDIR/conf/f2b_jail.conf
|
||||
" >"$YNH_APP_BASEDIR/conf/f2b_jail.conf"
|
||||
|
||||
echo "
|
||||
[INCLUDES]
|
||||
|
@ -96,13 +90,30 @@ before = common.conf
|
|||
[Definition]
|
||||
failregex = __FAILREGEX__
|
||||
ignoreregex =
|
||||
" >$YNH_APP_BASEDIR/conf/f2b_filter.conf
|
||||
" >"$YNH_APP_BASEDIR/conf/f2b_filter.conf"
|
||||
fi
|
||||
|
||||
ynh_add_config --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
|
||||
ynh_add_config --template="f2b_filter.conf" --destination="/etc/fail2ban/filter.d/$app.conf"
|
||||
|
||||
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
||||
# if "$logpath" doesn't exist (as if using --use_template argument), assign
|
||||
# "$logpath" using the one in the previously generated fail2ban conf file
|
||||
if [ -z "${logpath:-}" ]; then
|
||||
# the first sed deletes possibles spaces and the second one extract the path
|
||||
logpath=$(grep "^logpath" "/etc/fail2ban/jail.d/$app.conf" | sed "s/ //g" | sed "s/logpath=//g")
|
||||
fi
|
||||
|
||||
# Create the folder and logfile if they doesn't exist,
|
||||
# as fail2ban require an existing logfile before configuration
|
||||
mkdir -p "/var/log/$app"
|
||||
if [ ! -f "$logpath" ]; then
|
||||
touch "$logpath"
|
||||
fi
|
||||
# Make sure log folder's permissions are correct
|
||||
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
|
||||
|
||||
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
|
||||
if [[ -n "$fail2ban_error" ]]; then
|
|
@ -77,9 +77,9 @@ ynh_handle_getopts_args() {
|
|||
# And replace long option (value of the option_flag) by the short option, the option_flag itself
|
||||
# (e.g. for [u]=user, --user will be -u)
|
||||
# Replace long option with = (match the beginning of the argument)
|
||||
arguments[arg]="$(echo "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]}/-${option_flag} /")"
|
||||
arguments[arg]="$(printf '%s\n' "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]}/-${option_flag} /")"
|
||||
# And long option without = (match the whole line)
|
||||
arguments[arg]="$(echo "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]%=}$/-${option_flag} /")"
|
||||
arguments[arg]="$(printf '%s\n' "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]%=}$/-${option_flag} /")"
|
||||
done
|
||||
done
|
||||
|
241
helpers/helpers.v1.d/go
Normal file
241
helpers/helpers.v1.d/go
Normal file
|
@ -0,0 +1,241 @@
|
|||
#!/bin/bash
|
||||
|
||||
ynh_go_try_bash_extension() {
|
||||
if [ -x src/configure ]; then
|
||||
src/configure && make -C src || {
|
||||
ynh_print_info --message="Optional bash extension failed to build, but things will still work normally."
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
goenv_install_dir="/opt/goenv"
|
||||
go_version_path="$goenv_install_dir/versions"
|
||||
# goenv_ROOT is the directory of goenv, it needs to be loaded as a environment variable.
|
||||
export GOENV_ROOT="$goenv_install_dir"
|
||||
|
||||
# Load the version of Go for an app, and set variables.
|
||||
#
|
||||
# ynh_use_go has to be used in any app scripts before using Go for the first time.
|
||||
# This helper will provide alias and variables to use in your scripts.
|
||||
#
|
||||
# To use gem or Go, use the alias `ynh_gem` and `ynh_go`
|
||||
# Those alias will use the correct version installed for the app
|
||||
# For example: use `ynh_gem install` instead of `gem install`
|
||||
#
|
||||
# With `sudo` or `ynh_exec_as`, use instead the fallback variables `$ynh_gem` and `$ynh_go`
|
||||
# And propagate $PATH to sudo with $ynh_go_load_path
|
||||
# Exemple: `ynh_exec_as $app $ynh_go_load_path $ynh_gem install`
|
||||
#
|
||||
# $PATH contains the path of the requested version of Go.
|
||||
# However, $PATH is duplicated into $go_path to outlast any manipulation of $PATH
|
||||
# You can use the variable `$ynh_go_load_path` to quickly load your Go version
|
||||
# in $PATH for an usage into a separate script.
|
||||
# Exemple: `$ynh_go_load_path $install_dir/script_that_use_gem.sh`
|
||||
#
|
||||
#
|
||||
# Finally, to start a Go service with the correct version, 2 solutions
|
||||
# Either the app is dependent of Go or gem, but does not called it directly.
|
||||
# In such situation, you need to load PATH
|
||||
# `Environment="__YNH_GO_LOAD_PATH__"`
|
||||
# `ExecStart=__INSTALL_DIR__/my_app`
|
||||
# You will replace __YNH_GO_LOAD_PATH__ with $ynh_go_load_path
|
||||
#
|
||||
# Or Go start the app directly, then you don't need to load the PATH variable
|
||||
# `ExecStart=__YNH_GO__ my_app run`
|
||||
# You will replace __YNH_GO__ with $ynh_go
|
||||
#
|
||||
#
|
||||
# one other variable is also available
|
||||
# - $go_path: The absolute path to Go binaries for the chosen version.
|
||||
#
|
||||
# usage: ynh_use_go
|
||||
#
|
||||
# Requires YunoHost version 3.2.2 or higher.
|
||||
ynh_use_go () {
|
||||
go_version=$(ynh_app_setting_get --app=$app --key=go_version)
|
||||
|
||||
# Get the absolute path of this version of Go
|
||||
go_path="$go_version_path/$go_version/bin"
|
||||
|
||||
# Allow alias to be used into bash script
|
||||
shopt -s expand_aliases
|
||||
|
||||
# Create an alias for the specific version of Go and a variable as fallback
|
||||
ynh_go="$go_path/go"
|
||||
alias ynh_go="$ynh_go"
|
||||
|
||||
# Load the path of this version of Go in $PATH
|
||||
if [[ :$PATH: != *":$go_path"* ]]; then
|
||||
PATH="$go_path:$PATH"
|
||||
fi
|
||||
# Create an alias to easily load the PATH
|
||||
ynh_go_load_path="PATH=$PATH"
|
||||
|
||||
# Sets the local application-specific Go version
|
||||
pushd $install_dir
|
||||
$goenv_install_dir/bin/goenv local $go_version
|
||||
popd
|
||||
}
|
||||
|
||||
# Install a specific version of Go
|
||||
#
|
||||
# ynh_install_go will install the version of Go provided as argument by using goenv.
|
||||
#
|
||||
# This helper creates a /etc/profile.d/goenv.sh that configures PATH environment for goenv
|
||||
# for every LOGIN user, hence your user must have a defined shell (as opposed to /usr/sbin/nologin)
|
||||
#
|
||||
# Don't forget to execute go-dependent command in a login environment
|
||||
# (e.g. sudo --login option)
|
||||
# When not possible (e.g. in systemd service definition), please use direct path
|
||||
# to goenv shims (e.g. $goenv_ROOT/shims/bundle)
|
||||
#
|
||||
# usage: ynh_install_go --go_version=go_version
|
||||
# | arg: -v, --go_version= - Version of go to install.
|
||||
#
|
||||
# Requires YunoHost version 3.2.2 or higher.
|
||||
ynh_install_go () {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=v
|
||||
local -A args_array=( [v]=go_version= )
|
||||
local go_version
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Load goenv path in PATH
|
||||
local CLEAR_PATH="$goenv_install_dir/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Go prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
# Move an existing Go binary, to avoid to block goenv
|
||||
test -x /usr/bin/go && mv /usr/bin/go /usr/bin/go_goenv
|
||||
|
||||
# Install or update goenv
|
||||
mkdir -p $goenv_install_dir
|
||||
pushd "$goenv_install_dir"
|
||||
if ! [ -x "$goenv_install_dir/bin/goenv" ]; then
|
||||
ynh_print_info --message="Downloading goenv..."
|
||||
git init -q
|
||||
git remote add origin https://github.com/syndbg/goenv.git
|
||||
else
|
||||
ynh_print_info --message="Updating goenv..."
|
||||
fi
|
||||
git fetch -q --tags --prune origin
|
||||
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||
git checkout -q "$git_latest_tag"
|
||||
ynh_go_try_bash_extension
|
||||
goenv=$goenv_install_dir/bin/goenv
|
||||
popd
|
||||
|
||||
# Install or update xxenv-latest
|
||||
goenv_latest_dir="$goenv_install_dir/plugins/xxenv-latest"
|
||||
mkdir -p "$goenv_latest_dir"
|
||||
pushd "$goenv_latest_dir"
|
||||
if ! [ -x "$goenv_latest_dir/bin/goenv-latest" ]; then
|
||||
ynh_print_info --message="Downloading xxenv-latest..."
|
||||
git init -q
|
||||
git remote add origin https://github.com/momo-lab/xxenv-latest.git
|
||||
else
|
||||
ynh_print_info --message="Updating xxenv-latest..."
|
||||
fi
|
||||
git fetch -q --tags --prune origin
|
||||
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||
git checkout -q "$git_latest_tag"
|
||||
popd
|
||||
|
||||
# Enable caching
|
||||
mkdir -p "${goenv_install_dir}/cache"
|
||||
|
||||
# Create shims directory if needed
|
||||
mkdir -p "${goenv_install_dir}/shims"
|
||||
|
||||
# Restore /usr/local/bin in PATH
|
||||
PATH=$CLEAR_PATH
|
||||
|
||||
# And replace the old Go binary
|
||||
test -x /usr/bin/go_goenv && mv /usr/bin/go_goenv /usr/bin/go
|
||||
|
||||
# Install the requested version of Go
|
||||
local final_go_version=$("$goenv_latest_dir/bin/goenv-latest" --print "$go_version")
|
||||
ynh_print_info --message="Installation of Go-$final_go_version"
|
||||
goenv install --skip-existing "$final_go_version"
|
||||
|
||||
# Store go_version into the config of this app
|
||||
ynh_app_setting_set --app="$app" --key="go_version" --value="$final_go_version"
|
||||
|
||||
# Cleanup Go versions
|
||||
ynh_cleanup_go
|
||||
|
||||
# Set environment for Go users
|
||||
echo "#goenv
|
||||
export GOENV_ROOT=$goenv_install_dir
|
||||
export PATH=\"$goenv_install_dir/bin:$PATH\"
|
||||
eval \"\$(goenv init -)\"
|
||||
#goenv" > /etc/profile.d/goenv.sh
|
||||
|
||||
# Load the environment
|
||||
eval "$(goenv init -)"
|
||||
}
|
||||
|
||||
# Remove the version of Go used by the app.
|
||||
#
|
||||
# This helper will also cleanup Go versions
|
||||
#
|
||||
# usage: ynh_remove_go
|
||||
ynh_remove_go () {
|
||||
local go_version=$(ynh_app_setting_get --app="$app" --key="go_version")
|
||||
|
||||
# Load goenv path in PATH
|
||||
local CLEAR_PATH="$goenv_install_dir/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Go prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
# Remove the line for this app
|
||||
ynh_app_setting_delete --app="$app" --key="go_version"
|
||||
|
||||
# Cleanup Go versions
|
||||
ynh_cleanup_go
|
||||
}
|
||||
|
||||
# Remove no more needed versions of Go used by the app.
|
||||
#
|
||||
# This helper will check what Go version are no more required,
|
||||
# and uninstall them
|
||||
# If no app uses Go, goenv will be also removed.
|
||||
#
|
||||
# usage: ynh_cleanup_go
|
||||
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
|
||||
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
|
||||
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
|
||||
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
|
||||
# Remove goenv environment configuration
|
||||
ynh_print_info --message="Removing of goenv"
|
||||
ynh_secure_remove --file="$goenv_install_dir"
|
||||
ynh_secure_remove --file="/etc/profile.d/goenv.sh"
|
||||
fi
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
# Get the total or free amount of RAM+swap on the system
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_get_ram [--free|--total] [--ignore_swap|--only_swap]
|
||||
# | arg: -f, --free - Count free RAM+swap
|
||||
# | arg: -t, --total - Count total RAM+swap
|
||||
|
@ -63,6 +65,8 @@ ynh_get_ram() {
|
|||
|
||||
# Return 0 or 1 depending if the system has a given amount of RAM+swap free or total
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_require_ram --required=RAM [--free|--total] [--ignore_swap|--only_swap]
|
||||
# | arg: -r, --required= - The amount to require, in MB
|
||||
# | arg: -f, --free - Count free RAM+swap
|
|
@ -186,6 +186,26 @@ ynh_exec_fully_quiet() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Execute a command and redirect stderr in /dev/null. Print stderr on error.
|
||||
#
|
||||
# usage: ynh_exec_and_print_stderr_only_if_error your command and args
|
||||
# | arg: command - command to execute
|
||||
#
|
||||
# Note that you should NOT quote the command but only prefix it with ynh_exec_and_print_stderr_only_if_error
|
||||
#
|
||||
# Requires YunoHost version 11.2 or higher.
|
||||
ynh_exec_and_print_stderr_only_if_error() {
|
||||
logfile="$(mktemp)"
|
||||
rc=0
|
||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||
"$@" 2> "$logfile" || rc="$?"
|
||||
if (( rc != 0 )); then
|
||||
ynh_exec_warn cat "$logfile"
|
||||
ynh_secure_remove "$logfile"
|
||||
return "$rc"
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove any logs for all the following commands.
|
||||
#
|
||||
# usage: ynh_print_OFF
|
103
helpers/helpers.v1.d/logrotate
Normal file
103
helpers/helpers.v1.d/logrotate
Normal file
|
@ -0,0 +1,103 @@
|
|||
#!/bin/bash
|
||||
|
||||
FIRST_CALL_TO_LOGROTATE="true"
|
||||
|
||||
# Use logrotate to manage the logfile
|
||||
#
|
||||
# usage: ynh_use_logrotate [--logfile=/log/file] [--specific_user=user/group]
|
||||
# | arg: -l, --logfile= - absolute path of logfile
|
||||
# | arg: -u, --specific_user= - run logrotate as the specified user and group. If not specified logrotate is runned as root.
|
||||
#
|
||||
# If no `--logfile` is provided, `/var/log/$app` will be used as default.
|
||||
# `logfile` can point to a directory or a file.
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
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
|
||||
unset all_args[$I]
|
||||
fi
|
||||
done
|
||||
set -- "${all_args[@]}"
|
||||
|
||||
# Argument parsing
|
||||
local legacy_args=lu
|
||||
local -A args_array=([l]=logfile= [u]=specific_user=)
|
||||
local logfile
|
||||
local specific_user
|
||||
ynh_handle_getopts_args "$@"
|
||||
logfile="${logfile:-}"
|
||||
specific_user="${specific_user:-}"
|
||||
|
||||
set -o noglob
|
||||
if [[ -z "$logfile" ]]; then
|
||||
logfile="/var/log/${app}/*.log"
|
||||
elif [[ "${logfile##*.}" != "log" ]] && [[ "${logfile##*.}" != "txt" ]]; then
|
||||
logfile="$logfile/*.log"
|
||||
fi
|
||||
set +o noglob
|
||||
|
||||
for stuff in $logfile
|
||||
do
|
||||
mkdir --parents $(dirname "$stuff")
|
||||
done
|
||||
|
||||
local su_directive=""
|
||||
if [[ -n "$specific_user" ]]; then
|
||||
su_directive="su ${specific_user%/*} ${specific_user#*/}"
|
||||
fi
|
||||
|
||||
local tempconf="$(mktemp)"
|
||||
cat << EOF >$tempconf
|
||||
$logfile {
|
||||
# Rotate if the logfile exceeds 100Mo
|
||||
size 100M
|
||||
# Keep 12 old log maximum
|
||||
rotate 12
|
||||
# Compress the logs with gzip
|
||||
compress
|
||||
# Compress the log at the next cycle. So keep always 2 non compressed logs
|
||||
delaycompress
|
||||
# Copy and truncate the log to allow to continue write on it. Instead of moving the log.
|
||||
copytruncate
|
||||
# Do not trigger an error if the log is missing
|
||||
missingok
|
||||
# Do not rotate if the log is empty
|
||||
notifempty
|
||||
# Keep old logs in the same dir
|
||||
noolddir
|
||||
$su_directive
|
||||
}
|
||||
EOF
|
||||
|
||||
if [[ "$FIRST_CALL_TO_LOGROTATE" == "true" ]]
|
||||
then
|
||||
cat $tempconf > /etc/logrotate.d/$app
|
||||
else
|
||||
cat $tempconf >> /etc/logrotate.d/$app
|
||||
fi
|
||||
|
||||
FIRST_CALL_TO_LOGROTATE="false"
|
||||
|
||||
# Make sure permissions are correct (otherwise the config file could be ignored and the corresponding logs never rotated)
|
||||
chmod 644 "/etc/logrotate.d/$app"
|
||||
mkdir -p "/var/log/$app"
|
||||
chmod 750 "/var/log/$app"
|
||||
}
|
||||
|
||||
# Remove the app's logrotate config.
|
||||
#
|
||||
# usage: ynh_remove_logrotate
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_remove_logrotate() {
|
||||
if [ -e "/etc/logrotate.d/$app" ]; then
|
||||
rm "/etc/logrotate.d/$app"
|
||||
fi
|
||||
}
|
355
helpers/helpers.v1.d/mongodb
Normal file
355
helpers/helpers.v1.d/mongodb
Normal file
|
@ -0,0 +1,355 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Execute a mongo command
|
||||
#
|
||||
# example: ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("wekan")'
|
||||
# example: ynh_mongo_exec --command="db.getMongo().getDBNames().indexOf(\"wekan\")"
|
||||
#
|
||||
# usage: ynh_mongo_exec [--user=user] [--password=password] [--authenticationdatabase=authenticationdatabase] [--database=database] [--host=host] [--port=port] --command="command" [--eval]
|
||||
# | arg: -u, --user= - The user name to connect as
|
||||
# | arg: -p, --password= - The user password
|
||||
# | arg: -d, --authenticationdatabase= - The authenticationdatabase to connect to
|
||||
# | arg: -d, --database= - The database to connect to
|
||||
# | arg: -h, --host= - The host to connect to
|
||||
# | arg: -P, --port= - The port to connect to
|
||||
# | arg: -c, --command= - The command to evaluate
|
||||
# | arg: -e, --eval - Evaluate instead of execute the command.
|
||||
#
|
||||
#
|
||||
ynh_mongo_exec() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=upadhPce
|
||||
local -A args_array=( [u]=user= [p]=password= [a]=authenticationdatabase= [d]=database= [h]=host= [P]=port= [c]=command= [e]=eval )
|
||||
local user
|
||||
local password
|
||||
local authenticationdatabase
|
||||
local database
|
||||
local host
|
||||
local port
|
||||
local command
|
||||
local eval
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
user="${user:-}"
|
||||
password="${password:-}"
|
||||
authenticationdatabase="${authenticationdatabase:-}"
|
||||
database="${database:-}"
|
||||
host="${host:-}"
|
||||
port="${port:-}"
|
||||
eval=${eval:-0}
|
||||
|
||||
# If user is provided
|
||||
if [ -n "$user" ]
|
||||
then
|
||||
user="--username=$user"
|
||||
|
||||
# If password is provided
|
||||
if [ -n "$password" ]
|
||||
then
|
||||
password="--password=$password"
|
||||
fi
|
||||
|
||||
# If authenticationdatabase is provided
|
||||
if [ -n "$authenticationdatabase" ]
|
||||
then
|
||||
authenticationdatabase="--authenticationDatabase=$authenticationdatabase"
|
||||
else
|
||||
authenticationdatabase="--authenticationDatabase=admin"
|
||||
fi
|
||||
else
|
||||
password=""
|
||||
authenticationdatabase=""
|
||||
fi
|
||||
|
||||
# If host is provided
|
||||
if [ -n "$host" ]
|
||||
then
|
||||
host="--host=$host"
|
||||
fi
|
||||
|
||||
# If port is provided
|
||||
if [ -n "$port" ]
|
||||
then
|
||||
port="--port=$port"
|
||||
fi
|
||||
|
||||
# If eval is not provided
|
||||
if [ $eval -eq 0 ]
|
||||
then
|
||||
# If database is provided
|
||||
if [ -n "$database" ]
|
||||
then
|
||||
database="use $database"
|
||||
else
|
||||
database=""
|
||||
fi
|
||||
|
||||
mongosh --quiet --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port <<EOF
|
||||
$database
|
||||
${command}
|
||||
quit()
|
||||
EOF
|
||||
else
|
||||
# If database is provided
|
||||
if [ -n "$database" ]
|
||||
then
|
||||
database="$database"
|
||||
else
|
||||
database=""
|
||||
fi
|
||||
|
||||
mongosh --quiet $database --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port --eval="$command"
|
||||
fi
|
||||
}
|
||||
|
||||
# Drop a database
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# If you intend to drop the database *and* the associated user,
|
||||
# consider using ynh_mongo_remove_db instead.
|
||||
#
|
||||
# usage: ynh_mongo_drop_db --database=database
|
||||
# | arg: -d, --database= - The database name to drop
|
||||
#
|
||||
#
|
||||
ynh_mongo_drop_db() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=d
|
||||
local -A args_array=( [d]=database= )
|
||||
local database
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
ynh_mongo_exec --database="$database" --command='db.runCommand({dropDatabase: 1})'
|
||||
}
|
||||
|
||||
# Dump a database
|
||||
#
|
||||
# example: ynh_mongo_dump_db --database=wekan > ./dump.bson
|
||||
#
|
||||
# usage: ynh_mongo_dump_db --database=database
|
||||
# | arg: -d, --database= - The database name to dump
|
||||
# | ret: the mongodump output
|
||||
#
|
||||
#
|
||||
ynh_mongo_dump_db() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=d
|
||||
local -A args_array=( [d]=database= )
|
||||
local database
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
mongodump --quiet --db="$database" --archive
|
||||
}
|
||||
|
||||
# Create a user
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_mongo_create_user --db_user=user --db_pwd=pwd --db_name=name
|
||||
# | arg: -u, --db_user= - The user name to create
|
||||
# | arg: -p, --db_pwd= - The password to identify user by
|
||||
# | arg: -n, --db_name= - Name of the database to grant privilegies
|
||||
#
|
||||
#
|
||||
ynh_mongo_create_user() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=unp
|
||||
local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
|
||||
local db_user
|
||||
local db_name
|
||||
local db_pwd
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Create the user and set the user as admin of the db
|
||||
ynh_mongo_exec --database="$db_name" --command='db.createUser( { user: "'${db_user}'", pwd: "'${db_pwd}'", roles: [ { role: "readWrite", db: "'${db_name}'" } ] } );'
|
||||
|
||||
# Add clustermonitoring rights
|
||||
ynh_mongo_exec --database="$db_name" --command='db.grantRolesToUser("'${db_user}'",[{ role: "clusterMonitor", db: "admin" }]);'
|
||||
}
|
||||
|
||||
# Check if a mongo database exists
|
||||
#
|
||||
# usage: ynh_mongo_database_exists --database=database
|
||||
# | arg: -d, --database= - The database for which to check existence
|
||||
# | exit: Return 1 if the database doesn't exist, 0 otherwise
|
||||
#
|
||||
#
|
||||
ynh_mongo_database_exists() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=d
|
||||
local -A args_array=([d]=database=)
|
||||
local database
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")' --eval) -lt 0 ]
|
||||
then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Restore a database
|
||||
#
|
||||
# example: ynh_mongo_restore_db --database=wekan < ./dump.bson
|
||||
#
|
||||
# usage: ynh_mongo_restore_db --database=database
|
||||
# | arg: -d, --database= - The database name to restore
|
||||
#
|
||||
#
|
||||
ynh_mongo_restore_db() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=d
|
||||
local -A args_array=( [d]=database= )
|
||||
local database
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
mongorestore --quiet --db="$database" --archive
|
||||
}
|
||||
|
||||
# Drop a user
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_mongo_drop_user --db_user=user --db_name=name
|
||||
# | arg: -u, --db_user= - The user to drop
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
#
|
||||
#
|
||||
ynh_mongo_drop_user() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=un
|
||||
local -A args_array=( [u]=db_user= [n]=db_name= )
|
||||
local db_user
|
||||
local db_name
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
ynh_mongo_exec --database="$db_name" --command='db.dropUser("'$db_user'", {w: "majority", wtimeout: 5000})'
|
||||
}
|
||||
|
||||
# Create a database, an user and its password. Then store the password in the app's config
|
||||
#
|
||||
# usage: ynh_mongo_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
# | arg: -p, --db_pwd= - Password of the database. If not provided, a password will be generated
|
||||
#
|
||||
# After executing this helper, the password of the created database will be available in $db_pwd
|
||||
# It will also be stored as "mongopwd" into the app settings.
|
||||
#
|
||||
#
|
||||
ynh_mongo_setup_db() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=unp
|
||||
local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
|
||||
local db_user
|
||||
local db_name
|
||||
db_pwd=""
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
local new_db_pwd=$(ynh_string_random) # Generate a random password
|
||||
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd
|
||||
db_pwd="${db_pwd:-$new_db_pwd}"
|
||||
|
||||
# Create the user and grant access to the database
|
||||
ynh_mongo_create_user --db_user="$db_user" --db_pwd="$db_pwd" --db_name="$db_name"
|
||||
|
||||
# Store the password in the app's config
|
||||
ynh_app_setting_set --app=$app --key=db_pwd --value=$db_pwd
|
||||
}
|
||||
|
||||
# Remove a database if it exists, and the associated user
|
||||
#
|
||||
# usage: ynh_mongo_remove_db --db_user=user --db_name=name
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
#
|
||||
#
|
||||
ynh_mongo_remove_db() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=un
|
||||
local -A args_array=( [u]=db_user= [n]=db_name= )
|
||||
local db_user
|
||||
local db_name
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
if ynh_mongo_database_exists --database=$db_name; then # Check if the database exists
|
||||
ynh_mongo_drop_db --database=$db_name # Remove the database
|
||||
else
|
||||
ynh_print_warn --message="Database $db_name not found"
|
||||
fi
|
||||
|
||||
# Remove mongo user if it exists
|
||||
ynh_mongo_drop_user --db_user=$db_user --db_name=$db_name
|
||||
}
|
||||
|
||||
# Install MongoDB and integrate MongoDB service in YunoHost
|
||||
#
|
||||
# usage: ynh_install_mongo [--mongo_version=mongo_version]
|
||||
# | arg: -m, --mongo_version= - Version of MongoDB to install
|
||||
#
|
||||
#
|
||||
ynh_install_mongo() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=m
|
||||
local -A args_array=([m]=mongo_version=)
|
||||
local mongo_version
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
mongo_version="${mongo_version:-$YNH_MONGO_VERSION}"
|
||||
|
||||
ynh_print_info --message="Installing MongoDB Community Edition ..."
|
||||
local mongo_debian_release=$(ynh_get_debian_release)
|
||||
|
||||
if [[ "$(grep '^flags' /proc/cpuinfo | uniq)" != *"avx"* && "$mongo_version" != "4.4" ]]; then
|
||||
ynh_print_warn --message="Installing Mongo 4.4 as $mongo_version is not compatible with your cpu (see https://docs.mongodb.com/manual/administration/production-notes/#x86_64)."
|
||||
mongo_version="4.4"
|
||||
fi
|
||||
if [[ "$mongo_version" == "4.4" ]]; then
|
||||
ynh_print_warn --message="Switched to buster install as Mongo 4.4 is not compatible with $mongo_debian_release."
|
||||
mongo_debian_release=buster
|
||||
fi
|
||||
|
||||
ynh_install_extra_app_dependencies --repo="deb http://repo.mongodb.org/apt/debian $mongo_debian_release/mongodb-org/$mongo_version main" --package="mongodb-org mongodb-org-server mongodb-org-tools mongodb-mongosh" --key="https://www.mongodb.org/static/pgp/server-$mongo_version.asc"
|
||||
mongodb_servicename=mongod
|
||||
|
||||
# Make sure MongoDB is started and enabled
|
||||
systemctl enable $mongodb_servicename --quiet
|
||||
systemctl daemon-reload --quiet
|
||||
ynh_systemd_action --service_name=$mongodb_servicename --action=restart --line_match="aiting for connections" --log_path="/var/log/mongodb/$mongodb_servicename.log"
|
||||
|
||||
# Integrate MongoDB service in YunoHost
|
||||
yunohost service add $mongodb_servicename --description="MongoDB daemon" --log="/var/log/mongodb/$mongodb_servicename.log"
|
||||
|
||||
# Store mongo_version into the config of this app
|
||||
ynh_app_setting_set --app=$app --key=mongo_version --value=$mongo_version
|
||||
}
|
||||
|
||||
# Remove MongoDB
|
||||
# Only remove the MongoDB service integration in YunoHost for now
|
||||
# if MongoDB package as been removed
|
||||
#
|
||||
# usage: ynh_remove_mongo
|
||||
#
|
||||
#
|
||||
ynh_remove_mongo() {
|
||||
# Only remove the mongodb service if it is not installed.
|
||||
if ! ynh_package_is_installed --package="mongodb*"
|
||||
then
|
||||
ynh_print_info --message="Removing MongoDB service..."
|
||||
mongodb_servicename=mongod
|
||||
# Remove the mongodb service
|
||||
yunohost service remove $mongodb_servicename
|
||||
ynh_secure_remove --file="/var/lib/mongodb"
|
||||
ynh_secure_remove --file="/var/log/mongodb"
|
||||
fi
|
||||
}
|
|
@ -44,9 +44,9 @@ ynh_multimedia_build_main_dir() {
|
|||
|
||||
## Application des droits étendus sur le dossier multimedia.
|
||||
# Droit d'écriture pour le groupe et le groupe multimedia en acl et droit de lecture pour other:
|
||||
setfacl -RnL -m g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY"
|
||||
setfacl -RnL -m g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY" || true
|
||||
# Application de la même règle que précédemment, mais par défaut pour les nouveaux fichiers.
|
||||
setfacl -RnL -m d:g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY"
|
||||
setfacl -RnL -m d:g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY" || true
|
||||
# Réglage du masque par défaut. Qui garantie (en principe...) un droit maximal à rwx. Donc pas de restriction de droits par l'acl.
|
||||
setfacl -RL -m m::rwx "$MEDIA_DIRECTORY" || true
|
||||
}
|
|
@ -152,6 +152,8 @@ ynh_mysql_create_user() {
|
|||
|
||||
# Check if a mysql user exists
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_mysql_user_exists --user=user
|
||||
# | arg: -u, --user= - the user for which to check existence
|
||||
# | ret: 0 if the user exists, 1 otherwise.
|
||||
|
@ -172,6 +174,19 @@ ynh_mysql_user_exists() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Check if a mysql database exists
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_mysql_database_exists database
|
||||
# | arg: database - the database for which to check existence
|
||||
# | exit: Return 1 if the database doesn't exist, 0 otherwise
|
||||
#
|
||||
ynh_mysql_database_exists() {
|
||||
local database=$1
|
||||
mysqlshow | grep -qE "^|\s+$database\s+|"
|
||||
}
|
||||
|
||||
# Drop a user
|
||||
#
|
||||
# [internal]
|
||||
|
@ -186,6 +201,8 @@ ynh_mysql_drop_user() {
|
|||
|
||||
# Create a database, an user and its password. Then store the password in the app's config
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
|
@ -219,6 +236,8 @@ ynh_mysql_setup_db() {
|
|||
|
||||
# Remove a database if it exists, and the associated user
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
|
@ -233,7 +252,7 @@ ynh_mysql_remove_db() {
|
|||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
if mysqlshow | grep -q "^| $db_name "; then
|
||||
if ynh_mysql_database_exists "$db_name"; then
|
||||
ynh_mysql_drop_db $db_name
|
||||
else
|
||||
ynh_print_warn --message="Database $db_name not found"
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
# Find a free port and return it
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_find_port --port=begin_port
|
||||
# | arg: -p, --port= - port to start to search
|
||||
# | ret: the port number
|
||||
|
@ -26,6 +28,8 @@ ynh_find_port() {
|
|||
|
||||
# Test if a port is available
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_find_port --port=XYZ
|
||||
# | arg: -p, --port= - port to check
|
||||
# | ret: 0 if the port is available, 1 if it is already used by another process.
|
|
@ -44,35 +44,22 @@ ynh_remove_nginx_config() {
|
|||
}
|
||||
|
||||
|
||||
# Move / regen the nginx config in a change url context
|
||||
# Regen the nginx config in a change url context
|
||||
#
|
||||
# usage: ynh_change_url_nginx_config
|
||||
#
|
||||
# Requires YunoHost version 11.1.9 or higher.
|
||||
ynh_change_url_nginx_config() {
|
||||
|
||||
# Make a backup of the original NGINX config file if manually modified
|
||||
# (nb: this is possibly different from the same instruction called by
|
||||
# ynh_add_config inside ynh_add_nginx_config because the path may have
|
||||
# changed if we're changing the domain too...)
|
||||
local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
|
||||
local new_nginx_conf_path=/etc/nginx/conf.d/$new_domain.d/$app.conf
|
||||
|
||||
# Change the path in the NGINX config file
|
||||
if [ $change_path -eq 1 ]
|
||||
then
|
||||
# Make a backup of the original NGINX config file if modified
|
||||
ynh_backup_if_checksum_is_different --file="$old_nginx_conf_path"
|
||||
# Set global variables for NGINX helper
|
||||
domain="$old_domain"
|
||||
path="$new_path"
|
||||
path_url="$new_path"
|
||||
# Create a dedicated NGINX config
|
||||
ynh_add_nginx_config
|
||||
fi
|
||||
|
||||
# Change the domain for NGINX
|
||||
if [ $change_domain -eq 1 ]
|
||||
then
|
||||
ynh_delete_file_checksum --file="$old_nginx_conf_path"
|
||||
mv "$old_nginx_conf_path" "$new_nginx_conf_path"
|
||||
ynh_store_file_checksum --file="$new_nginx_conf_path"
|
||||
fi
|
||||
ynh_systemd_action --service_name=nginx --action=reload
|
||||
}
|
||||
ynh_secure_remove --file="$old_nginx_conf_path"
|
||||
|
||||
# Regen the nginx conf
|
||||
ynh_add_nginx_config
|
||||
}
|
|
@ -74,6 +74,8 @@ ynh_use_nodejs() {
|
|||
ynh_node_load_PATH="PATH=$node_PATH"
|
||||
# Same var but in lower case to be compatible with ynh_replace_vars...
|
||||
ynh_node_load_path="PATH=$node_PATH"
|
||||
# Prevent yet another Node and Corepack madness, with Corepack wanting the user to confirm download of Yarn
|
||||
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
||||
}
|
||||
|
||||
# Install a specific version of nodejs
|
||||
|
@ -81,7 +83,7 @@ ynh_use_nodejs() {
|
|||
# ynh_install_nodejs will install the version of node provided as argument by using n.
|
||||
#
|
||||
# usage: ynh_install_nodejs --nodejs_version=nodejs_version
|
||||
# | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed.
|
||||
# | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0).
|
||||
#
|
||||
# `n` (Node version management) uses the `PATH` variable to store the path of the version of node it is going to use.
|
||||
# That's how it changes the version
|
||||
|
@ -113,7 +115,7 @@ ynh_install_nodejs() {
|
|||
|
||||
# Install (or update if YunoHost vendor/ folder updated since last install) n
|
||||
mkdir -p $n_install_dir/bin/
|
||||
cp /usr/share/yunohost/helpers.d/vendor/n/n $n_install_dir/bin/n
|
||||
cp "$YNH_HELPERS_DIR/vendor/n/n" $n_install_dir/bin/n
|
||||
# Tweak for n to understand it's installed in $N_PREFIX
|
||||
ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n"
|
||||
|
||||
|
@ -142,14 +144,11 @@ ynh_install_nodejs() {
|
|||
fi
|
||||
|
||||
# Store the ID of this app and the version of node requested for it
|
||||
echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
||||
echo "$app:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
||||
|
||||
# Store nodejs_version into the config of this app
|
||||
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
|
||||
|
||||
# Build the update script and set the cronjob
|
||||
ynh_cron_upgrade_node
|
||||
|
||||
ynh_use_nodejs
|
||||
}
|
||||
|
||||
|
@ -166,7 +165,7 @@ ynh_remove_nodejs() {
|
|||
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
||||
|
||||
# Remove the line for this app
|
||||
sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
||||
sed --in-place "/$app:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
||||
|
||||
# If no other app uses this version of nodejs, remove it.
|
||||
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"; then
|
||||
|
@ -178,62 +177,5 @@ ynh_remove_nodejs() {
|
|||
ynh_secure_remove --file="$n_install_dir"
|
||||
ynh_secure_remove --file="/usr/local/n"
|
||||
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
||||
rm --force /etc/cron.daily/node_update
|
||||
fi
|
||||
}
|
||||
|
||||
# Set a cron design to update your node versions
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# This cron will check and update all minor node versions used by your apps.
|
||||
#
|
||||
# usage: ynh_cron_upgrade_node
|
||||
#
|
||||
# Requires YunoHost version 2.7.12 or higher.
|
||||
ynh_cron_upgrade_node() {
|
||||
# Build the update script
|
||||
cat >"$n_install_dir/node_update.sh" <<EOF
|
||||
#!/bin/bash
|
||||
|
||||
version_path="$node_version_path"
|
||||
n_install_dir="$n_install_dir"
|
||||
|
||||
# Log the date
|
||||
date
|
||||
|
||||
# List all real installed version of node
|
||||
all_real_version="\$(find \$version_path/* -maxdepth 0 -type d | sed "s@\$version_path/@@g")"
|
||||
|
||||
# Keep only the major version number of each line
|
||||
all_real_version=\$(echo "\$all_real_version" | sed 's/\..*\$//')
|
||||
|
||||
# Remove double entries
|
||||
all_real_version=\$(echo "\$all_real_version" | sort --unique)
|
||||
|
||||
# Read each major version
|
||||
while read version
|
||||
do
|
||||
echo "Update of the version \$version"
|
||||
sudo \$n_install_dir/bin/n \$version
|
||||
|
||||
# Find the last "real" version for this major version of node.
|
||||
real_nodejs_version=\$(find \$version_path/\$version* -maxdepth 0 | sort --version-sort | tail --lines=1)
|
||||
real_nodejs_version=\$(basename \$real_nodejs_version)
|
||||
|
||||
# Update the symbolic link for this version
|
||||
sudo ln --symbolic --force --no-target-directory \$version_path/\$real_nodejs_version \$version_path/\$version
|
||||
done <<< "\$(echo "\$all_real_version")"
|
||||
EOF
|
||||
|
||||
chmod +x "$n_install_dir/node_update.sh"
|
||||
|
||||
# Build the cronjob
|
||||
cat >"/etc/cron.daily/node_update" <<EOF
|
||||
#!/bin/bash
|
||||
|
||||
$n_install_dir/node_update.sh >> $n_install_dir/node_update.log
|
||||
EOF
|
||||
|
||||
chmod +x "/etc/cron.daily/node_update"
|
||||
}
|
|
@ -1,39 +1,50 @@
|
|||
#!/bin/bash
|
||||
|
||||
readonly YNH_DEFAULT_PHP_VERSION=7.4
|
||||
readonly YNH_DEFAULT_PHP_VERSION=8.2
|
||||
# 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}
|
||||
|
||||
# Create a dedicated PHP-FPM config
|
||||
#
|
||||
# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] [--package=packages] [--dedicated_service]
|
||||
# | arg: -v, --phpversion= - Version of PHP to use.
|
||||
# | arg: -t, --use_template - Use this helper in template mode.
|
||||
# | arg: -p, --package= - Additionnal PHP packages to install
|
||||
# | arg: -d, --dedicated_service - Use a dedicated PHP-FPM service instead of the common one.
|
||||
# usage: ynh_add_fpm_config
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# Case 1 (recommended) : your provided a snippet conf/extra_php-fpm.conf
|
||||
#
|
||||
# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] [--dedicated_service]
|
||||
# | arg: -v, --phpversion= - Version of PHP to use.
|
||||
# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high).
|
||||
# The actual PHP configuration will be automatically generated,
|
||||
# and your extra_php-fpm.conf will be appended (typically contains PHP upload limits)
|
||||
#
|
||||
# The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf
|
||||
#
|
||||
# Performance-related options in the PHP conf, such as :
|
||||
# pm.max_children, pm.start_servers, pm.min_spare_servers pm.max_spare_servers
|
||||
# are computed from two parameters called "usage" and "footprint" which can be set to low/medium/high. (cf details below)
|
||||
#
|
||||
# If you wish to tweak those, please initialize the settings `fpm_usage` and `fpm_footprint`
|
||||
# *prior* to calling this helper. Otherwise, "low" will be used as a default for both values.
|
||||
#
|
||||
# Otherwise, if you want the user to have control over these, we encourage to create a config panel
|
||||
# (which should ultimately be standardized by the core ...)
|
||||
#
|
||||
# Case 2 (deprecate) : you provided an entire conf/php-fpm.conf
|
||||
#
|
||||
# The configuration will be hydrated, replacing __FOOBAR__ placeholders with $foobar values, etc.
|
||||
#
|
||||
# The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf
|
||||
#
|
||||
# ----------------------
|
||||
#
|
||||
# fpm_footprint: Memory footprint of the service (low/medium/high).
|
||||
# low - Less than 20 MB of RAM by pool.
|
||||
# medium - Between 20 MB and 40 MB of RAM by pool.
|
||||
# high - More than 40 MB of RAM by pool.
|
||||
# Or specify exactly the footprint, the load of the service as MB by pool instead of having a standard value.
|
||||
# To have this value, use the following command and stress the service.
|
||||
# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP
|
||||
# N - Or you can specify a quantitative footprint as MB by pool (use watch -n0.5 ps -o user,cmd,%cpu,rss -u APP)
|
||||
#
|
||||
# | arg: -u, --usage= - Expected usage of the service (low/medium/high).
|
||||
# fpm_usage: Expected usage of the service (low/medium/high).
|
||||
# low - Personal usage, behind the SSO.
|
||||
# medium - Low usage, few people or/and publicly accessible.
|
||||
# high - High usage, frequently visited website.
|
||||
#
|
||||
# | arg: -p, --package= - Additionnal PHP packages to install for a specific version of PHP
|
||||
# | arg: -d, --dedicated_service - Use a dedicated PHP-FPM service instead of the common one.
|
||||
#
|
||||
#
|
||||
# The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM.
|
||||
# So it will be used to defined 'pm.max_children'
|
||||
# A lower value for the footprint will allow more children for 'pm.max_children'. And so for
|
||||
|
@ -59,27 +70,40 @@ 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=vtufpd
|
||||
local -A args_array=([v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
|
||||
local legacy_args=vufg
|
||||
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [g]=group=)
|
||||
local group
|
||||
local phpversion
|
||||
local use_template
|
||||
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.
|
||||
use_template="${use_template:-1}"
|
||||
local autogenconf=false
|
||||
usage="${usage:-}"
|
||||
footprint="${footprint:-}"
|
||||
if [ -n "$usage" ] || [ -n "$footprint" ]; then
|
||||
use_template=0
|
||||
if [ -n "$usage" ] || [ -n "$footprint" ] || [[ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]]; then
|
||||
autogenconf=true
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
|
@ -103,45 +127,17 @@ ynh_add_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
|
||||
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 [ $use_template -eq 1 ]; then
|
||||
if [ $autogenconf == "false" ]; then
|
||||
# Usage 1, use the template in conf/php-fpm.conf
|
||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||
# Make sure now that the template indeed exists
|
||||
|
@ -149,19 +145,16 @@ ynh_add_fpm_config() {
|
|||
else
|
||||
# Usage 2, generate a PHP-FPM config file with ynh_get_scalable_phpfpm
|
||||
|
||||
# Store settings
|
||||
ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint
|
||||
ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage
|
||||
|
||||
# Define the values to use for the configuration of PHP.
|
||||
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
|
||||
|
||||
local phpfpm_group=$([[ -n "$group" ]] && echo "$group" || echo "$app")
|
||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||
echo "
|
||||
[__APP__]
|
||||
|
||||
user = __APP__
|
||||
group = __APP__
|
||||
group = __PHPFPM_GROUP__
|
||||
|
||||
chdir = __INSTALL_DIR__
|
||||
|
||||
|
@ -173,19 +166,19 @@ pm = __PHP_PM__
|
|||
pm.max_children = __PHP_MAX_CHILDREN__
|
||||
pm.max_requests = 500
|
||||
request_terminate_timeout = 1d
|
||||
" >$phpfpm_path
|
||||
" >"$phpfpm_path"
|
||||
|
||||
if [ "$php_pm" = "dynamic" ]; then
|
||||
echo "
|
||||
pm.start_servers = __PHP_START_SERVERS__
|
||||
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
|
||||
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
|
||||
" >>$phpfpm_path
|
||||
" >>"$phpfpm_path"
|
||||
|
||||
elif [ "$php_pm" = "ondemand" ]; then
|
||||
echo "
|
||||
pm.process_idle_timeout = 10s
|
||||
" >>$phpfpm_path
|
||||
" >>"$phpfpm_path"
|
||||
fi
|
||||
|
||||
# Concatene the extra config.
|
||||
|
@ -197,48 +190,6 @@ 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
|
||||
|
@ -246,7 +197,6 @@ WantedBy=multi-user.target
|
|||
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
|
||||
|
@ -257,8 +207,6 @@ WantedBy=multi-user.target
|
|||
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)
|
||||
|
||||
|
@ -272,69 +220,7 @@ 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
|
||||
|
@ -473,84 +359,3 @@ ynh_get_scalable_phpfpm() {
|
|||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
readonly YNH_DEFAULT_COMPOSER_VERSION=1.10.17
|
||||
# Declare the actual composer version to use.
|
||||
# A packager willing to use another version of composer can override the variable into its _common.sh.
|
||||
YNH_COMPOSER_VERSION=${YNH_COMPOSER_VERSION:-$YNH_DEFAULT_COMPOSER_VERSION}
|
||||
|
||||
# Execute a command with Composer
|
||||
#
|
||||
# usage: ynh_composer_exec [--phpversion=phpversion] [--workdir=$install_dir] --commands="commands"
|
||||
# | arg: -v, --phpversion - PHP version to use with composer
|
||||
# | arg: -w, --workdir - The directory from where the command will be executed. Default $install_dir or $final_path
|
||||
# | arg: -c, --commands - Commands to execute.
|
||||
#
|
||||
# Requires YunoHost version 4.2 or higher.
|
||||
ynh_composer_exec() {
|
||||
local _globalphpversion=${phpversion-:}
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=vwc
|
||||
declare -Ar args_array=([v]=phpversion= [w]=workdir= [c]=commands=)
|
||||
local phpversion
|
||||
local workdir
|
||||
local commands
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
workdir="${workdir:-${install_dir:-$final_path}}"
|
||||
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||
else
|
||||
phpversion="${phpversion:-$_globalphpversion}"
|
||||
fi
|
||||
|
||||
COMPOSER_HOME="$workdir/.composer" COMPOSER_MEMORY_LIMIT=-1 \
|
||||
php${phpversion} "$workdir/composer.phar" $commands \
|
||||
-d "$workdir" --no-interaction --no-ansi 2>&1
|
||||
}
|
||||
|
||||
# Install and initialize Composer in the given directory
|
||||
#
|
||||
# usage: ynh_install_composer [--phpversion=phpversion] [--workdir=$install_dir] [--install_args="--optimize-autoloader"] [--composerversion=composerversion]
|
||||
# | arg: -v, --phpversion - PHP version to use with composer
|
||||
# | arg: -w, --workdir - The directory from where the command will be executed. Default $install_dir.
|
||||
# | arg: -a, --install_args - Additional arguments provided to the composer install. Argument --no-dev already include
|
||||
# | arg: -c, --composerversion - Composer version to install
|
||||
#
|
||||
# Requires YunoHost version 4.2 or higher.
|
||||
ynh_install_composer() {
|
||||
local _globalphpversion=${phpversion-:}
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=vwac
|
||||
declare -Ar args_array=([v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
|
||||
local phpversion
|
||||
local workdir
|
||||
local install_args
|
||||
local composerversion
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
workdir="${workdir:-$final_path}"
|
||||
else
|
||||
workdir="${workdir:-$install_dir}"
|
||||
fi
|
||||
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||
else
|
||||
phpversion="${phpversion:-$_globalphpversion}"
|
||||
fi
|
||||
|
||||
install_args="${install_args:-}"
|
||||
composerversion="${composerversion:-$YNH_COMPOSER_VERSION}"
|
||||
|
||||
curl -sS https://getcomposer.org/installer \
|
||||
| COMPOSER_HOME="$workdir/.composer" \
|
||||
php${phpversion} -- --quiet --install-dir="$workdir" --version=$composerversion \
|
||||
|| ynh_die --message="Unable to install Composer."
|
||||
|
||||
# install dependencies
|
||||
ynh_composer_exec --phpversion="${phpversion}" --workdir="$workdir" --commands="install --no-dev $install_args" \
|
||||
|| ynh_die --message="Unable to install core dependencies with Composer."
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
||||
PSQL_VERSION=13
|
||||
PSQL_VERSION=15
|
||||
|
||||
# Open a connection as a user
|
||||
#
|
||||
|
@ -160,6 +160,8 @@ ynh_psql_create_user() {
|
|||
|
||||
# Check if a psql user exists
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_psql_user_exists --user=user
|
||||
# | arg: -u, --user= - the user for which to check existence
|
||||
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
||||
|
@ -222,6 +224,8 @@ ynh_psql_drop_user() {
|
|||
|
||||
# Create a database, an user and its password. Then store the password in the app's config
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
||||
|
@ -257,6 +261,8 @@ ynh_psql_setup_db() {
|
|||
|
||||
# Remove a database if it exists, and the associated user
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_psql_remove_db --db_user=user --db_name=name
|
||||
# | arg: -u, --db_user= - Owner of the database
|
||||
# | arg: -n, --db_name= - Name of the database
|
39
helpers/helpers.v1.d/redis
Normal file
39
helpers/helpers.v1.d/redis
Normal file
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
|
||||
# get the first available redis database
|
||||
#
|
||||
# usage: ynh_redis_get_free_db
|
||||
# | returns: the database number to use
|
||||
ynh_redis_get_free_db() {
|
||||
local result max db
|
||||
result=$(redis-cli INFO keyspace)
|
||||
|
||||
# get the num
|
||||
max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+")
|
||||
|
||||
db=0
|
||||
# default Debian setting is 15 databases
|
||||
for i in $(seq 0 "$max")
|
||||
do
|
||||
if ! echo "$result" | grep -q "db$i"
|
||||
then
|
||||
db=$i
|
||||
break 1
|
||||
fi
|
||||
db=-1
|
||||
done
|
||||
|
||||
test "$db" -eq -1 && ynh_die --message="No available Redis databases..."
|
||||
|
||||
echo "$db"
|
||||
}
|
||||
|
||||
# Create a master password and set up global settings
|
||||
# Please always call this script in install and restore scripts
|
||||
#
|
||||
# usage: ynh_redis_remove_db database
|
||||
# | arg: database - the database to erase
|
||||
ynh_redis_remove_db() {
|
||||
local db=$1
|
||||
redis-cli -n "$db" flushdb
|
||||
}
|
306
helpers/helpers.v1.d/ruby
Normal file
306
helpers/helpers.v1.d/ruby
Normal file
|
@ -0,0 +1,306 @@
|
|||
#!/bin/bash
|
||||
|
||||
rbenv_install_dir="/opt/rbenv"
|
||||
ruby_version_path="$rbenv_install_dir/versions"
|
||||
|
||||
# RBENV_ROOT is the directory of rbenv, it needs to be loaded as a environment variable.
|
||||
export RBENV_ROOT="$rbenv_install_dir"
|
||||
export rbenv_root="$rbenv_install_dir"
|
||||
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
||||
build_ruby_dependencies="libjemalloc-dev curl build-essential libreadline-dev zlib1g-dev libsqlite3-dev libssl-dev libxml2-dev libxslt-dev autoconf automake bison libtool"
|
||||
build_pkg_dependencies="${build_pkg_dependencies:-} $build_ruby_dependencies"
|
||||
fi
|
||||
|
||||
# Load the version of Ruby for an app, and set variables.
|
||||
#
|
||||
# ynh_use_ruby has to be used in any app scripts before using Ruby for the first time.
|
||||
# This helper will provide alias and variables to use in your scripts.
|
||||
#
|
||||
# To use gem or Ruby, use the alias `ynh_gem` and `ynh_ruby`
|
||||
# Those alias will use the correct version installed for the app
|
||||
# For example: use `ynh_gem install` instead of `gem install`
|
||||
#
|
||||
# With `sudo` or `ynh_exec_as`, use instead the fallback variables `$ynh_gem` and `$ynh_ruby`
|
||||
# And propagate $PATH to sudo with $ynh_ruby_load_path
|
||||
# Exemple: `ynh_exec_as $app $ynh_ruby_load_path $ynh_gem install`
|
||||
#
|
||||
# $PATH contains the path of the requested version of Ruby.
|
||||
# However, $PATH is duplicated into $ruby_path to outlast any manipulation of $PATH
|
||||
# You can use the variable `$ynh_ruby_load_path` to quickly load your Ruby version
|
||||
# in $PATH for an usage into a separate script.
|
||||
# Exemple: $ynh_ruby_load_path $final_path/script_that_use_gem.sh`
|
||||
#
|
||||
#
|
||||
# Finally, to start a Ruby service with the correct version, 2 solutions
|
||||
# Either the app is dependent of Ruby or gem, but does not called it directly.
|
||||
# In such situation, you need to load PATH
|
||||
# `Environment="__YNH_RUBY_LOAD_PATH__"`
|
||||
# `ExecStart=__FINALPATH__/my_app`
|
||||
# You will replace __YNH_RUBY_LOAD_PATH__ with $ynh_ruby_load_path
|
||||
#
|
||||
# Or Ruby start the app directly, then you don't need to load the PATH variable
|
||||
# `ExecStart=__YNH_RUBY__ my_app run`
|
||||
# You will replace __YNH_RUBY__ with $ynh_ruby
|
||||
#
|
||||
#
|
||||
# one other variable is also available
|
||||
# - $ruby_path: The absolute path to Ruby binaries for the chosen version.
|
||||
#
|
||||
# usage: ynh_use_ruby
|
||||
#
|
||||
# Requires YunoHost version 3.2.2 or higher.
|
||||
ynh_use_ruby () {
|
||||
ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version)
|
||||
|
||||
# Get the absolute path of this version of Ruby
|
||||
ruby_path="$ruby_version_path/$app/bin"
|
||||
|
||||
# Allow alias to be used into bash script
|
||||
shopt -s expand_aliases
|
||||
|
||||
# Create an alias for the specific version of Ruby and a variable as fallback
|
||||
ynh_ruby="$ruby_path/ruby"
|
||||
alias ynh_ruby="$ynh_ruby"
|
||||
# And gem
|
||||
ynh_gem="$ruby_path/gem"
|
||||
alias ynh_gem="$ynh_gem"
|
||||
|
||||
# Load the path of this version of Ruby in $PATH
|
||||
if [[ :$PATH: != *":$ruby_path"* ]]; then
|
||||
PATH="$ruby_path:$PATH"
|
||||
fi
|
||||
# Create an alias to easily load the PATH
|
||||
ynh_ruby_load_path="PATH=$PATH"
|
||||
|
||||
# Sets the local application-specific Ruby version
|
||||
pushd ${install_dir:-$final_path}
|
||||
$rbenv_install_dir/bin/rbenv local $ruby_version
|
||||
popd
|
||||
}
|
||||
|
||||
# Install a specific version of Ruby
|
||||
#
|
||||
# ynh_install_ruby will install the version of Ruby provided as argument by using rbenv.
|
||||
#
|
||||
# This helper creates a /etc/profile.d/rbenv.sh that configures PATH environment for rbenv
|
||||
# for every LOGIN user, hence your user must have a defined shell (as opposed to /usr/sbin/nologin)
|
||||
#
|
||||
# Don't forget to execute ruby-dependent command in a login environment
|
||||
# (e.g. sudo --login option)
|
||||
# When not possible (e.g. in systemd service definition), please use direct path
|
||||
# to rbenv shims (e.g. $RBENV_ROOT/shims/bundle)
|
||||
#
|
||||
# usage: ynh_install_ruby --ruby_version=ruby_version
|
||||
# | arg: -v, --ruby_version= - Version of ruby to install.
|
||||
#
|
||||
# Requires YunoHost version 3.2.2 or higher.
|
||||
ynh_install_ruby () {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=v
|
||||
local -A args_array=( [v]=ruby_version= )
|
||||
local ruby_version
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Load rbenv path in PATH
|
||||
local CLEAR_PATH="$rbenv_install_dir/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Ruby prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
# Move an existing Ruby binary, to avoid to block rbenv
|
||||
test -x /usr/bin/ruby && mv /usr/bin/ruby /usr/bin/ruby_rbenv
|
||||
|
||||
# Install or update rbenv
|
||||
mkdir -p $rbenv_install_dir
|
||||
rbenv="$(command -v rbenv $rbenv_install_dir/bin/rbenv | grep "$rbenv_install_dir/bin/rbenv" | head -1)"
|
||||
if [ -n "$rbenv" ]; then
|
||||
pushd "${rbenv%/*/*}"
|
||||
if git remote -v 2>/dev/null | grep "https://github.com/rbenv/rbenv.git"; then
|
||||
ynh_print_info --message="Updating rbenv..."
|
||||
git pull -q --tags origin master
|
||||
ynh_ruby_try_bash_extension
|
||||
else
|
||||
ynh_print_info --message="Reinstalling rbenv..."
|
||||
cd ..
|
||||
ynh_secure_remove --file=$rbenv_install_dir
|
||||
mkdir -p $rbenv_install_dir
|
||||
cd $rbenv_install_dir
|
||||
git init -q
|
||||
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
|
||||
git checkout -q -b master origin/master
|
||||
ynh_ruby_try_bash_extension
|
||||
rbenv=$rbenv_install_dir/bin/rbenv
|
||||
fi
|
||||
popd
|
||||
else
|
||||
ynh_print_info --message="Installing rbenv..."
|
||||
pushd $rbenv_install_dir
|
||||
git init -q
|
||||
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
|
||||
git checkout -q -b master origin/master
|
||||
ynh_ruby_try_bash_extension
|
||||
rbenv=$rbenv_install_dir/bin/rbenv
|
||||
popd
|
||||
fi
|
||||
|
||||
mkdir -p "${rbenv_install_dir}/plugins"
|
||||
|
||||
ruby_build="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-install rbenv-install | head -1)"
|
||||
if [ -n "$ruby_build" ]; then
|
||||
pushd "${ruby_build%/*/*}"
|
||||
if git remote -v 2>/dev/null | grep "https://github.com/rbenv/ruby-build.git"; then
|
||||
ynh_print_info --message="Updating ruby-build..."
|
||||
git pull -q origin master
|
||||
fi
|
||||
popd
|
||||
else
|
||||
ynh_print_info --message="Installing ruby-build..."
|
||||
git clone -q https://github.com/rbenv/ruby-build.git "${rbenv_install_dir}/plugins/ruby-build"
|
||||
fi
|
||||
|
||||
rbenv_alias="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-alias rbenv-alias | head -1)"
|
||||
if [ -n "$rbenv_alias" ]; then
|
||||
pushd "${rbenv_alias%/*/*}"
|
||||
if git remote -v 2>/dev/null | grep "https://github.com/tpope/rbenv-aliases.git"; then
|
||||
ynh_print_info --message="Updating rbenv-aliases..."
|
||||
git pull -q origin master
|
||||
fi
|
||||
popd
|
||||
else
|
||||
ynh_print_info --message="Installing rbenv-aliases..."
|
||||
git clone -q https://github.com/tpope/rbenv-aliases.git "${rbenv_install_dir}/plugins/rbenv-aliase"
|
||||
fi
|
||||
|
||||
rbenv_latest="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-latest rbenv-latest | head -1)"
|
||||
if [ -n "$rbenv_latest" ]; then
|
||||
pushd "${rbenv_latest%/*/*}"
|
||||
if git remote -v 2>/dev/null | grep "https://github.com/momo-lab/xxenv-latest.git"; then
|
||||
ynh_print_info --message="Updating xxenv-latest..."
|
||||
git pull -q origin master
|
||||
fi
|
||||
popd
|
||||
else
|
||||
ynh_print_info --message="Installing xxenv-latest..."
|
||||
git clone -q https://github.com/momo-lab/xxenv-latest.git "${rbenv_install_dir}/plugins/xxenv-latest"
|
||||
fi
|
||||
|
||||
# Enable caching
|
||||
mkdir -p "${rbenv_install_dir}/cache"
|
||||
|
||||
# Create shims directory if needed
|
||||
mkdir -p "${rbenv_install_dir}/shims"
|
||||
|
||||
# Restore /usr/local/bin in PATH
|
||||
PATH=$CLEAR_PATH
|
||||
|
||||
# And replace the old Ruby binary
|
||||
test -x /usr/bin/ruby_rbenv && mv /usr/bin/ruby_rbenv /usr/bin/ruby
|
||||
|
||||
# Install the requested version of Ruby
|
||||
local final_ruby_version=$(rbenv latest --print $ruby_version)
|
||||
if ! [ -n "$final_ruby_version" ]; then
|
||||
final_ruby_version=$ruby_version
|
||||
fi
|
||||
ynh_print_info --message="Installing Ruby $final_ruby_version"
|
||||
RUBY_CONFIGURE_OPTS="--disable-install-doc --with-jemalloc" MAKE_OPTS="-j2" rbenv install --skip-existing $final_ruby_version > /dev/null 2>&1
|
||||
|
||||
# Store ruby_version into the config of this app
|
||||
ynh_app_setting_set --app=$app --key=ruby_version --value=$final_ruby_version
|
||||
|
||||
# Remove app virtualenv
|
||||
if rbenv alias --list | grep --quiet "$app "
|
||||
then
|
||||
rbenv alias $app --remove
|
||||
fi
|
||||
|
||||
# Create app virtualenv
|
||||
rbenv alias $app $final_ruby_version
|
||||
|
||||
# Cleanup Ruby versions
|
||||
ynh_cleanup_ruby
|
||||
|
||||
# Set environment for Ruby users
|
||||
echo "#rbenv
|
||||
export RBENV_ROOT=$rbenv_install_dir
|
||||
export PATH=\"$rbenv_install_dir/bin:$PATH\"
|
||||
eval \"\$(rbenv init -)\"
|
||||
#rbenv" > /etc/profile.d/rbenv.sh
|
||||
|
||||
# Load the environment
|
||||
eval "$(rbenv init -)"
|
||||
}
|
||||
|
||||
# Remove the version of Ruby used by the app.
|
||||
#
|
||||
# This helper will also cleanup Ruby versions
|
||||
#
|
||||
# usage: ynh_remove_ruby
|
||||
ynh_remove_ruby () {
|
||||
local ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version)
|
||||
|
||||
# Load rbenv path in PATH
|
||||
local CLEAR_PATH="$rbenv_install_dir/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Ruby prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
rbenv alias $app --remove
|
||||
|
||||
# Remove the line for this app
|
||||
ynh_app_setting_delete --app=$app --key=ruby_version
|
||||
|
||||
# Cleanup Ruby versions
|
||||
ynh_cleanup_ruby
|
||||
}
|
||||
|
||||
# Remove no more needed versions of Ruby used by the app.
|
||||
#
|
||||
# This helper will check what Ruby version are no more required,
|
||||
# and uninstall them
|
||||
# If no app uses Ruby, rbenv will be also removed.
|
||||
#
|
||||
# usage: ynh_cleanup_ruby
|
||||
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
|
||||
local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version")
|
||||
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
|
||||
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
|
||||
# Remove rbenv environment configuration
|
||||
ynh_print_info --message="Removing rbenv"
|
||||
ynh_secure_remove --file="$rbenv_install_dir"
|
||||
ynh_secure_remove --file="/etc/profile.d/rbenv.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
ynh_ruby_try_bash_extension() {
|
||||
if [ -x src/configure ]; then
|
||||
src/configure && make -C src || {
|
||||
ynh_print_info --message="Optional bash extension failed to build, but things will still work normally."
|
||||
}
|
||||
fi
|
||||
}
|
|
@ -18,11 +18,7 @@ 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
|
||||
|
@ -45,9 +41,41 @@ 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"
|
||||
}
|
||||
|
||||
# Set an application setting but only if the "$key" variable ain't set yet
|
||||
#
|
||||
# Note that it doesn't just define the setting but ALSO define the $foobar variable
|
||||
#
|
||||
# Hence it's meant as a replacement for this legacy overly complex syntax:
|
||||
#
|
||||
# if [ -z "${foo:-}" ]
|
||||
# then
|
||||
# foo="bar"
|
||||
# ynh_app_setting_set --key="foo" --value="$foo"
|
||||
# fi
|
||||
#
|
||||
# usage: ynh_app_setting_set_default --app=app --key=key --value=value
|
||||
# | arg: -a, --app= - the application id
|
||||
# | arg: -k, --key= - the setting name to set
|
||||
# | arg: -v, --value= - the default setting value to set
|
||||
#
|
||||
# Requires YunoHost version 11.1.16 or higher.
|
||||
ynh_app_setting_set_default() {
|
||||
local _globalapp=${app-:}
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=akv
|
||||
local -A args_array=([a]=app= [k]=key= [v]=value=)
|
||||
local app
|
||||
local key
|
||||
local value
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
app="${app:-$_globalapp}"
|
||||
|
||||
if [ -z "${!key:-}" ]; then
|
||||
eval $key=\$value
|
||||
ynh_app_setting "set" "$app" "$key" "$value"
|
||||
fi
|
||||
}
|
||||
|
@ -70,11 +98,7 @@ 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
|
||||
|
@ -113,6 +137,8 @@ EOF
|
|||
|
||||
# Check availability of a web path
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_webpath_available --domain=domain --path_url=path
|
||||
# | arg: -d, --domain= - the domain/host of the url
|
||||
# | arg: -p, --path_url= - the web path to check the availability of
|
||||
|
@ -134,6 +160,8 @@ ynh_webpath_available() {
|
|||
|
||||
# Register/book a web path for an app
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
|
||||
# | arg: -a, --app= - the app for which the domain should be registered
|
||||
# | arg: -d, --domain= - the domain/host of the web path
|
300
helpers/helpers.v1.d/sources
Normal file
300
helpers/helpers.v1.d/sources
Normal file
|
@ -0,0 +1,300 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Download, check integrity, uncompress and patch the source from app.src
|
||||
#
|
||||
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]
|
||||
# | arg: -d, --dest_dir= - Directory where to setup sources
|
||||
# | arg: -s, --source_id= - Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise
|
||||
# | arg: -k, --keep= - Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs' (no trailing `/` for folders)
|
||||
# | arg: -r, --full_replace= - Remove previous sources before installing new sources (can be 1 or 0, default to 0)
|
||||
#
|
||||
# ##### New 'sources' resources
|
||||
#
|
||||
# (See also the resources documentation which may be more complete?)
|
||||
#
|
||||
# This helper will read infos from the 'sources' resources in the manifest.toml of the app
|
||||
# and expect a structure like:
|
||||
#
|
||||
# ```toml
|
||||
# [resources.sources]
|
||||
# [resources.sources.main]
|
||||
# url = "https://some.address.to/download/the/app/archive"
|
||||
# sha256 = "0123456789abcdef" # The sha256 sum of the asset obtained from the URL
|
||||
# ```
|
||||
#
|
||||
# ##### Optional flags
|
||||
#
|
||||
# ```text
|
||||
# format = "tar.gz"/xz/bz2 # automatically guessed from the extension of the URL, but can be set explicitly. Will use `tar` to extract
|
||||
# "zip" # automatically guessed from the extension of the URL, but can be set explicitly. Will use `unzip` to extract
|
||||
# "docker" # useful to extract files from an already-built docker image (instead of rebuilding them locally). Will use `docker-image-extract` to extract
|
||||
# "whatever" # an arbitrary value, not really meaningful except to imply that the file won't be extracted
|
||||
#
|
||||
# in_subdir = true # default, there's an intermediate subdir in the archive before accessing the actual files
|
||||
# false # sources are directly in the archive root
|
||||
# n # (special cases) an integer representing a number of subdirs levels to get rid of
|
||||
#
|
||||
# extract = true # default if file is indeed an archive such as .zip, .tar.gz, .tar.bz2, ...
|
||||
# = false # default if file 'format' is not set and the file is not to be extracted because it is not an archive but a script or binary or whatever asset.
|
||||
# # in which case the file will only be `mv`ed to the location possibly renamed using the `rename` value
|
||||
#
|
||||
# rename = "whatever_your_want" # to be used for convenience when `extract` is false and the default name of the file is not practical
|
||||
# platform = "linux/amd64" # (defaults to "linux/$YNH_ARCH") to be used in conjonction with `format = "docker"` to specify which architecture to extract for
|
||||
# ```
|
||||
#
|
||||
# You may also define assets url and checksum per-architectures such as:
|
||||
# ```toml
|
||||
# [resources.sources]
|
||||
# [resources.sources.main]
|
||||
# amd64.url = "https://some.address.to/download/the/app/archive/when/amd64"
|
||||
# amd64.sha256 = "0123456789abcdef"
|
||||
# armhf.url = "https://some.address.to/download/the/app/archive/when/armhf"
|
||||
# armhf.sha256 = "fedcba9876543210"
|
||||
# ```
|
||||
#
|
||||
# In which case `ynh_setup_source --dest_dir="$install_dir"` will automatically pick the appropriate source depending on the arch
|
||||
#
|
||||
# The helper will:
|
||||
# - Download the specific URL if there is no local archive
|
||||
# - Check the integrity with the specific sha256 sum
|
||||
# - Uncompress the archive to `$dest_dir`.
|
||||
# - If `in_subdir` is true, the first level directory of the archive will be removed.
|
||||
# - If `in_subdir` is a numeric value, the N first level directories will be removed.
|
||||
# - Patches named `sources/patches/${src_id}-*.patch` will be applied to `$dest_dir`
|
||||
# - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_setup_source() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=dsk
|
||||
local -A args_array=([d]=dest_dir= [s]=source_id= [k]=keep= [r]=full_replace=)
|
||||
local dest_dir
|
||||
local source_id
|
||||
local keep
|
||||
local full_replace
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
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
|
||||
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
|
||||
local arch_prefix=""
|
||||
else
|
||||
local arch_prefix=".$YNH_ARCH"
|
||||
fi
|
||||
|
||||
local src_url="$(jq -r "$arch_prefix.url" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_sum="$(jq -r "$arch_prefix.sha256" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_sumprg="sha256sum"
|
||||
local src_format="$(jq -r ".format" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_in_subdir="$(jq -r ".in_subdir" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_extract="$(jq -r ".extract" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_platform="$(jq -r ".platform" <<< "$sources_json" | sed 's/^null$//')"
|
||||
local src_rename="$(jq -r ".rename" <<< "$sources_json" | sed 's/^null$//')"
|
||||
|
||||
[[ -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
|
||||
src_format="zip"
|
||||
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
|
||||
src_format="tar.xz"
|
||||
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]
|
||||
then
|
||||
src_format="tar.bz2"
|
||||
elif [[ -z "$src_extract" ]]
|
||||
then
|
||||
src_extract="false"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
source_id="${source_id:-app}"
|
||||
local src_file_path="$YNH_APP_BASEDIR/conf/${source_id}.src"
|
||||
|
||||
# Load value from configuration file (see above for a small doc about this file
|
||||
# format)
|
||||
local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_rename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
local src_platform=$(grep 'SOURCE_PLATFORM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||
fi
|
||||
|
||||
# Default value
|
||||
src_sumprg=${src_sumprg:-sha256sum}
|
||||
src_in_subdir=${src_in_subdir:-true}
|
||||
src_format=${src_format:-tar.gz}
|
||||
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
|
||||
src_extract=${src_extract:-true}
|
||||
|
||||
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}"
|
||||
|
||||
# Gotta use this trick with 'dirname' because source_id may contain slashes x_x
|
||||
mkdir -p $(dirname /var/cache/yunohost/download/${YNH_APP_ID}/${source_id})
|
||||
src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${source_id}"
|
||||
|
||||
if [ "$src_format" = "docker" ]; then
|
||||
src_platform="${src_platform:-"linux/$YNH_ARCH"}"
|
||||
else
|
||||
if test -e "$local_src"; then
|
||||
cp $local_src $src_filename
|
||||
fi
|
||||
|
||||
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
||||
|
||||
# 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
|
||||
rm -f "$src_filename"
|
||||
fi
|
||||
|
||||
# Only redownload the file if it wasnt prefetched
|
||||
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 ...
|
||||
local out
|
||||
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
||||
out=$(wget --tries 3 --no-dns-cache --timeout 900 --no-verbose --output-document=$src_filename $src_url 2>&1) \
|
||||
|| ynh_die --message="$out"
|
||||
fi
|
||||
|
||||
# Check the control sum
|
||||
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}
|
||||
ynh_die --message="Corrupt source for ${src_url}: Expected sha256sum to be ${src_sum} but got ${actual_sum} (size: ${actual_size})."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Keep files to be backup/restored at the end of the helper
|
||||
# Assuming $dest_dir already exists
|
||||
rm -rf /var/cache/yunohost/files_to_keep_during_setup_source/
|
||||
if [ -n "$keep" ] && [ -e "$dest_dir" ]; then
|
||||
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
||||
mkdir -p $keep_dir
|
||||
local stuff_to_keep
|
||||
for stuff_to_keep in $keep; do
|
||||
if [ -e "$dest_dir/$stuff_to_keep" ]; then
|
||||
mkdir --parents "$(dirname "$keep_dir/$stuff_to_keep")"
|
||||
cp --archive "$dest_dir/$stuff_to_keep" "$keep_dir/$stuff_to_keep"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$full_replace" -eq 1 ]; then
|
||||
ynh_secure_remove --file="$dest_dir"
|
||||
fi
|
||||
|
||||
# Extract source into the app dir
|
||||
mkdir --parents "$dest_dir"
|
||||
|
||||
if [ -n "${install_dir:-}" ] && [ "$dest_dir" == "$install_dir" ]; then
|
||||
_ynh_apply_default_permissions $dest_dir
|
||||
fi
|
||||
if [ -n "${final_path:-}" ] && [ "$dest_dir" == "$final_path" ]; then
|
||||
_ynh_apply_default_permissions $dest_dir
|
||||
fi
|
||||
|
||||
if [[ "$src_extract" == "false" ]]; then
|
||||
if [[ -z "$src_rename" ]]
|
||||
then
|
||||
mv $src_filename $dest_dir
|
||||
else
|
||||
mv $src_filename $dest_dir/$src_rename
|
||||
fi
|
||||
elif [[ "$src_format" == "docker" ]]; then
|
||||
"$YNH_HELPERS_DIR/vendor/docker-image-extract/docker-image-extract" -p $src_platform -o $dest_dir $src_url 2>&1
|
||||
elif [[ "$src_format" == "zip" ]]; then
|
||||
# Zip format
|
||||
# Using of a temp directory, because unzip doesn't manage --strip-components
|
||||
if $src_in_subdir; then
|
||||
local tmp_dir=$(mktemp --directory)
|
||||
unzip -quo $src_filename -d "$tmp_dir"
|
||||
cp --archive $tmp_dir/*/. "$dest_dir"
|
||||
ynh_secure_remove --file="$tmp_dir"
|
||||
else
|
||||
unzip -quo $src_filename -d "$dest_dir"
|
||||
fi
|
||||
ynh_secure_remove --file="$src_filename"
|
||||
else
|
||||
local strip=""
|
||||
if [ "$src_in_subdir" != "false" ]; then
|
||||
if [ "$src_in_subdir" == "true" ]; then
|
||||
local sub_dirs=1
|
||||
else
|
||||
local sub_dirs="$src_in_subdir"
|
||||
fi
|
||||
strip="--strip-components $sub_dirs"
|
||||
fi
|
||||
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]]; then
|
||||
tar --extract --file=$src_filename --directory="$dest_dir" $strip
|
||||
else
|
||||
ynh_die --message="Archive format unrecognized."
|
||||
fi
|
||||
ynh_secure_remove --file="$src_filename"
|
||||
fi
|
||||
|
||||
# Apply patches
|
||||
if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]; then
|
||||
local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/)
|
||||
if (($(find $patches_folder -type f -name "${source_id}-*.patch" 2>/dev/null | wc --lines) > "0")); then
|
||||
pushd "$dest_dir"
|
||||
for p in $patches_folder/${source_id}-*.patch; do
|
||||
echo $p
|
||||
patch --strip=1 <$p || ynh_print_warn --message="Packagers /!\\ patch $p failed to apply"
|
||||
done
|
||||
popd
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add supplementary files
|
||||
if test -e "$YNH_APP_BASEDIR/sources/extra_files/${source_id}"; then
|
||||
cp --archive $YNH_APP_BASEDIR/sources/extra_files/$source_id/. "$dest_dir"
|
||||
fi
|
||||
|
||||
# Keep files to be backup/restored at the end of the helper
|
||||
# Assuming $dest_dir already exists
|
||||
if [ -n "$keep" ]; then
|
||||
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
||||
local stuff_to_keep
|
||||
for stuff_to_keep in $keep; do
|
||||
if [ -e "$keep_dir/$stuff_to_keep" ]; then
|
||||
mkdir --parents "$(dirname "$dest_dir/$stuff_to_keep")"
|
||||
|
||||
# We add "--no-target-directory" (short option is -T) to handle the special case
|
||||
# when we "keep" a folder, but then the new setup already contains the same dir (but possibly empty)
|
||||
# in which case a regular "cp" will create a copy of the directory inside the directory ...
|
||||
# resulting in something like /var/www/$app/data/data instead of /var/www/$app/data
|
||||
# cf https://unix.stackexchange.com/q/94831 for a more elaborate explanation on the option
|
||||
cp --archive --no-target-directory "$keep_dir/$stuff_to_keep" "$dest_dir/$stuff_to_keep"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
rm -rf /var/cache/yunohost/files_to_keep_during_setup_source/
|
||||
}
|
|
@ -91,6 +91,8 @@ ynh_replace_special_string() {
|
|||
|
||||
# Sanitize a string intended to be the name of a database
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_sanitize_dbid --db_name=name
|
||||
# | arg: -n, --db_name= - name to correct/sanitize
|
||||
# | ret: the corrected name
|
|
@ -128,6 +128,7 @@ ynh_systemd_action() {
|
|||
if [[ -n "${line_match:-}" ]]; then
|
||||
set +x
|
||||
local i=0
|
||||
local starttime=$(date +%s)
|
||||
for i in $(seq 1 $timeout); do
|
||||
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
|
||||
if [ "$log_path" == "systemd" ]; then
|
||||
|
@ -145,6 +146,14 @@ ynh_systemd_action() {
|
|||
if [ $i -eq 30 ]; then
|
||||
echo "(this may take some time)" >&2
|
||||
fi
|
||||
# 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
|
||||
i=$timeout
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
set -x
|
|
@ -1,61 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Check if a YunoHost user exists
|
||||
#
|
||||
# usage: ynh_user_exists --username=username
|
||||
# | arg: -u, --username= - the username to check
|
||||
# | ret: 0 if the user exists, 1 otherwise.
|
||||
#
|
||||
# example: ynh_user_exists 'toto' || echo "User does not exist"
|
||||
#
|
||||
# Requires YunoHost version 2.2.4 or higher.
|
||||
ynh_user_exists() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=u
|
||||
local -A args_array=([u]=username=)
|
||||
local username
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
yunohost user list --output-as json --quiet | jq -e ".users.\"${username}\"" >/dev/null
|
||||
}
|
||||
|
||||
# Retrieve a YunoHost user information
|
||||
#
|
||||
# usage: ynh_user_get_info --username=username --key=key
|
||||
# | arg: -u, --username= - the username to retrieve info from
|
||||
# | arg: -k, --key= - the key to retrieve
|
||||
# | ret: the value associate to that key
|
||||
#
|
||||
# example: mail=$(ynh_user_get_info --username="toto" --key=mail)
|
||||
#
|
||||
# Requires YunoHost version 2.2.4 or higher.
|
||||
ynh_user_get_info() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=uk
|
||||
local -A args_array=([u]=username= [k]=key=)
|
||||
local username
|
||||
local key
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
yunohost user info "$username" --output-as json --quiet | jq -r ".$key"
|
||||
}
|
||||
|
||||
# Get the list of YunoHost users
|
||||
#
|
||||
# usage: ynh_user_list
|
||||
# | ret: one username per line as strings
|
||||
#
|
||||
# example: for u in $(ynh_user_list); do ... ; done
|
||||
#
|
||||
# Requires YunoHost version 2.4.0 or higher.
|
||||
ynh_user_list() {
|
||||
yunohost user list --output-as json --quiet | jq -r ".users | keys[]"
|
||||
}
|
||||
|
||||
# Check if a user exists on the system
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_system_user_exists --username=username
|
||||
# | arg: -u, --username= - the username to check
|
||||
# | ret: 0 if the user exists, 1 otherwise.
|
||||
|
@ -74,6 +22,8 @@ ynh_system_user_exists() {
|
|||
|
||||
# Check if a group exists on the system
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_system_group_exists --group=group
|
||||
# | arg: -g, --group= - the group to check
|
||||
# | ret: 0 if the group exists, 1 otherwise.
|
407
helpers/helpers.v1.d/templating
Normal file
407
helpers/helpers.v1.d/templating
Normal file
|
@ -0,0 +1,407 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Create a dedicated config file from a template
|
||||
#
|
||||
# usage: ynh_add_config --template="template" --destination="destination"
|
||||
# | arg: -t, --template= - Template config file to use
|
||||
# | arg: -d, --destination= - Destination of the config file
|
||||
# | arg: -j, --jinja - Use jinja template instead of the simple `__MY_VAR__` templating format
|
||||
#
|
||||
# examples:
|
||||
# ynh_add_config --template=".env" --destination="$install_dir/.env" # (use the template file "conf/.env" from the app's package)
|
||||
# ynh_add_config --jinja --template="config.j2" --destination="$install_dir/config" # (use the template file "conf/config.j2" from the app's package)
|
||||
#
|
||||
# The template can be by default the name of a file in the conf directory
|
||||
# of a YunoHost Package, a relative path or an absolute path.
|
||||
#
|
||||
# The helper will use the template `template` to generate a config file
|
||||
# `destination` by replacing the following keywords with global variables
|
||||
# that should be defined before calling this helper :
|
||||
# ```
|
||||
# __PATH__ by $path_url
|
||||
# __NAME__ by $app
|
||||
# __NAMETOCHANGE__ by $app
|
||||
# __USER__ by $app
|
||||
# __FINALPATH__ by $final_path
|
||||
# __PHPVERSION__ by $YNH_PHP_VERSION (packaging v1 only, packaging v2 uses phpversion setting implicitly set by apt resource)
|
||||
# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH
|
||||
# ```
|
||||
# And any dynamic variables that should be defined before calling this helper like:
|
||||
# ```
|
||||
# __DOMAIN__ by $domain
|
||||
# __APP__ by $app
|
||||
# __VAR_1__ by $var_1
|
||||
# __VAR_2__ by $var_2
|
||||
# ```
|
||||
#
|
||||
# ##### When --jinja is enabled
|
||||
#
|
||||
# This option is meant for advanced use-cases where the "simple" templating
|
||||
# mode ain't enough because you need conditional blocks or loops.
|
||||
#
|
||||
# For a full documentation of jinja's syntax you can refer to:
|
||||
# https://jinja.palletsprojects.com/en/3.1.x/templates/
|
||||
#
|
||||
# Note that in YunoHost context, all variables are from shell variables and therefore are strings
|
||||
#
|
||||
# ##### Keeping track of manual changes by the admin
|
||||
#
|
||||
# The helper will verify the checksum and backup the destination file
|
||||
# if it's different before applying the new template.
|
||||
#
|
||||
# And it will calculate and store the destination file checksum
|
||||
# into the app settings when configuration is done.
|
||||
#
|
||||
# Requires YunoHost version 4.1.0 or higher.
|
||||
ynh_add_config() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=tdj
|
||||
local -A args_array=([t]=template= [d]=destination= [j]=jinja)
|
||||
local template
|
||||
local destination
|
||||
local jinja
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
local template_path
|
||||
jinja="${jinja:-0}"
|
||||
|
||||
if [ -f "$YNH_APP_BASEDIR/conf/$template" ]; then
|
||||
template_path="$YNH_APP_BASEDIR/conf/$template"
|
||||
elif [ -f "$template" ]; then
|
||||
template_path=$template
|
||||
else
|
||||
ynh_die --message="The provided template $template doesn't exist"
|
||||
fi
|
||||
|
||||
ynh_backup_if_checksum_is_different --file="$destination"
|
||||
|
||||
# Make sure to set the permissions before we copy the file
|
||||
# This is to cover a case where an attacker could have
|
||||
# created a file beforehand to have control over it
|
||||
# (cp won't overwrite ownership / modes by default...)
|
||||
touch $destination
|
||||
chmod 640 $destination
|
||||
_ynh_apply_default_permissions $destination
|
||||
|
||||
if [[ "$jinja" == 1 ]]
|
||||
then
|
||||
# This is ran in a subshell such that the "export" does not "contaminate" the main process
|
||||
(
|
||||
export $(compgen -v)
|
||||
j2 "$template_path" -f env -o $destination
|
||||
)
|
||||
else
|
||||
cp -f "$template_path" "$destination"
|
||||
ynh_replace_vars --file="$destination"
|
||||
fi
|
||||
|
||||
ynh_store_file_checksum --file="$destination"
|
||||
}
|
||||
|
||||
# Replace variables in a file
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_replace_vars --file="file"
|
||||
# | arg: -f, --file= - File where to replace variables
|
||||
#
|
||||
# The helper will replace the following keywords with global variables
|
||||
# that should be defined before calling this helper :
|
||||
# __PATH__ by $path_url
|
||||
# __NAME__ by $app
|
||||
# __NAMETOCHANGE__ by $app
|
||||
# __USER__ by $app
|
||||
# __FINALPATH__ by $final_path
|
||||
# __PHPVERSION__ by $YNH_PHP_VERSION (packaging v1 only, packaging v2 uses phpversion setting implicitly set by apt resource)
|
||||
# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH
|
||||
#
|
||||
# And any dynamic variables that should be defined before calling this helper like:
|
||||
# __DOMAIN__ by $domain
|
||||
# __APP__ by $app
|
||||
# __VAR_1__ by $var_1
|
||||
# __VAR_2__ by $var_2
|
||||
#
|
||||
# Requires YunoHost version 4.1.0 or higher.
|
||||
ynh_replace_vars() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=f
|
||||
local -A args_array=([f]=file=)
|
||||
local file
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
# Replace specific YunoHost variables
|
||||
if test -n "${path_url:-}"; then
|
||||
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
|
||||
local path_url_slash_less=${path_url%/}
|
||||
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$file"
|
||||
ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$file"
|
||||
fi
|
||||
if test -n "${app:-}"; then
|
||||
ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$file"
|
||||
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$file"
|
||||
ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$file"
|
||||
fi
|
||||
# Legacy
|
||||
if test -n "${final_path:-}"; then
|
||||
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$file"
|
||||
ynh_replace_string --match_string="__INSTALL_DIR__" --replace_string="$final_path" --target_file="$file"
|
||||
fi
|
||||
# Legacy / Packaging v1 only
|
||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2 && test -n "${YNH_PHP_VERSION:-}"; then
|
||||
ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$file"
|
||||
fi
|
||||
if test -n "${ynh_node_load_PATH:-}"; then
|
||||
ynh_replace_string --match_string="__YNH_NODE_LOAD_PATH__" --replace_string="$ynh_node_load_PATH" --target_file="$file"
|
||||
fi
|
||||
|
||||
# Replace others variables
|
||||
|
||||
# List other unique (__ __) variables in $file
|
||||
local uniques_vars=($(grep -oP '__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__' $file | sort --unique | sed "s@__\([^.]*\)__@\L\1@g"))
|
||||
|
||||
set +o xtrace # set +x
|
||||
|
||||
# Do the replacement
|
||||
local delimit=@
|
||||
for one_var in "${uniques_vars[@]}"; do
|
||||
# Validate that one_var is indeed defined
|
||||
# -v checks if the variable is defined, for example:
|
||||
# -v FOO tests if $FOO is defined
|
||||
# -v $FOO tests if ${!FOO} is defined
|
||||
# More info: https://stackoverflow.com/questions/3601515/how-to-check-if-a-variable-is-set-in-bash/17538964#comment96392525_17538964
|
||||
[[ -v "${one_var:-}" ]] || ynh_die --message="Variable \$$one_var wasn't initialized when trying to replace __${one_var^^}__ in $file"
|
||||
|
||||
# Escape delimiter in match/replace string
|
||||
match_string="__${one_var^^}__"
|
||||
match_string=${match_string//${delimit}/"\\${delimit}"}
|
||||
replace_string="${!one_var}"
|
||||
replace_string=${replace_string//\\/\\\\}
|
||||
replace_string=${replace_string//${delimit}/"\\${delimit}"}
|
||||
|
||||
# Actually replace (sed is used instead of ynh_replace_string to avoid triggering an epic amount of debug logs)
|
||||
sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$file"
|
||||
done
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Get a value from heterogeneous file (yaml, json, php, python...)
|
||||
#
|
||||
# usage: ynh_read_var_in_file --file=PATH --key=KEY
|
||||
# | arg: -f, --file= - the path to the file
|
||||
# | arg: -k, --key= - the key to get
|
||||
# | arg: -a, --after= - the line just before the key (in case of multiple lines with the name of the key in the file)
|
||||
#
|
||||
# This helpers match several var affectation use case in several languages
|
||||
# We don't use jq or equivalent to keep comments and blank space in files
|
||||
# This helpers work line by line, it is not able to work correctly
|
||||
# if you have several identical keys in your files
|
||||
#
|
||||
# Example of line this helpers can managed correctly
|
||||
# .yml
|
||||
# title: YunoHost documentation
|
||||
# email: 'yunohost@yunohost.org'
|
||||
# .json
|
||||
# "theme": "colib'ris",
|
||||
# "port": 8102
|
||||
# "some_boolean": false,
|
||||
# "user": null
|
||||
# .ini
|
||||
# some_boolean = On
|
||||
# action = "Clear"
|
||||
# port = 20
|
||||
# .php
|
||||
# $user=
|
||||
# user => 20
|
||||
# .py
|
||||
# USER = 8102
|
||||
# user = 'https://donate.local'
|
||||
# CUSTOM['user'] = 'YunoHost'
|
||||
#
|
||||
# Requires YunoHost version 4.3 or higher.
|
||||
ynh_read_var_in_file() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=fka
|
||||
local -A args_array=([f]=file= [k]=key= [a]=after=)
|
||||
local file
|
||||
local key
|
||||
local after
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
after="${after:-}"
|
||||
|
||||
[[ -f $file ]] || ynh_die --message="File $file does not exists"
|
||||
|
||||
set +o xtrace # set +x
|
||||
|
||||
# Get the line number after which we search for the variable
|
||||
local line_number=1
|
||||
if [[ -n "$after" ]]; then
|
||||
line_number=$(grep -m1 -n $after $file | cut -d: -f1)
|
||||
if [[ -z "$line_number" ]]; then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local filename="$(basename -- "$file")"
|
||||
local ext="${filename##*.}"
|
||||
local endline=',;'
|
||||
local assign="=>|:|="
|
||||
local comments="#"
|
||||
local string="\"'"
|
||||
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
|
||||
endline='#'
|
||||
fi
|
||||
if [[ "$ext" =~ ^ini|env$ ]]; then
|
||||
comments="[;#]"
|
||||
fi
|
||||
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
|
||||
comments="//"
|
||||
fi
|
||||
local list='\[\s*['$string']?\w+['$string']?\]'
|
||||
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
|
||||
var_part+="[$string]?${key}[$string]?"
|
||||
var_part+='\s*\]?\s*'
|
||||
var_part+="($assign)"
|
||||
var_part+='\s*'
|
||||
|
||||
# Extract the part after assignation sign
|
||||
local expression_with_comment="$((tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)"
|
||||
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
|
||||
set -o xtrace # set -x
|
||||
echo YNH_NULL
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove comments if needed
|
||||
local expression="$(echo "$expression_with_comment" | sed "s@${comments}[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||
|
||||
local first_char="${expression:0:1}"
|
||||
if [[ "$first_char" == '"' ]]; then
|
||||
echo "$expression" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
|
||||
elif [[ "$first_char" == "'" ]]; then
|
||||
echo "$expression" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
|
||||
else
|
||||
echo "$expression"
|
||||
fi
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Set a value into heterogeneous file (yaml, json, php, python...)
|
||||
#
|
||||
# usage: ynh_write_var_in_file --file=PATH --key=KEY --value=VALUE
|
||||
# | arg: -f, --file= - the path to the file
|
||||
# | arg: -k, --key= - the key to set
|
||||
# | arg: -v, --value= - the value to set
|
||||
# | arg: -a, --after= - the line just before the key (in case of multiple lines with the name of the key in the file)
|
||||
#
|
||||
# Requires YunoHost version 4.3 or higher.
|
||||
ynh_write_var_in_file() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=fkva
|
||||
local -A args_array=([f]=file= [k]=key= [v]=value= [a]=after=)
|
||||
local file
|
||||
local key
|
||||
local value
|
||||
local after
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
after="${after:-}"
|
||||
|
||||
[[ -f $file ]] || ynh_die --message="File $file does not exists"
|
||||
|
||||
set +o xtrace # set +x
|
||||
|
||||
# Get the line number after which we search for the variable
|
||||
local after_line_number=1
|
||||
if [[ -n "$after" ]]; then
|
||||
after_line_number=$(grep -m1 -n $after $file | cut -d: -f1)
|
||||
if [[ -z "$after_line_number" ]]; then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local filename="$(basename -- "$file")"
|
||||
local ext="${filename##*.}"
|
||||
local endline=',;'
|
||||
local assign="=>|:|="
|
||||
local comments="#"
|
||||
local string="\"'"
|
||||
if [[ "$ext" =~ ^ini|env|toml|yml|yaml$ ]]; then
|
||||
endline='#'
|
||||
fi
|
||||
if [[ "$ext" =~ ^ini|env$ ]]; then
|
||||
comments="[;#]"
|
||||
fi
|
||||
if [[ "php" == "$ext" ]] || [[ "$ext" == "js" ]]; then
|
||||
comments="//"
|
||||
fi
|
||||
local list='\[\s*['$string']?\w+['$string']?\]'
|
||||
local var_part='^\s*((const|var|let)\s+)?\$?(\w+('$list')*(->|\.|\[))*\s*'
|
||||
var_part+="[$string]?${key}[$string]?"
|
||||
var_part+='\s*\]?\s*'
|
||||
var_part+="($assign)"
|
||||
var_part+='\s*'
|
||||
|
||||
# Extract the part after assignation sign
|
||||
local expression_with_comment="$((tail +$after_line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)"
|
||||
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
local value_line_number="$(tail +$after_line_number ${file} | grep -m1 -n -i -P $var_part'\K.*$' | cut -d: -f1)"
|
||||
value_line_number=$((after_line_number + value_line_number))
|
||||
local range="${after_line_number},${value_line_number} "
|
||||
|
||||
# Remove comments if needed
|
||||
local expression="$(echo "$expression_with_comment" | sed "s@${comments}[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||
endline=${expression_with_comment#"$expression"}
|
||||
endline="$(echo "$endline" | sed 's/\\/\\\\/g')"
|
||||
value="$(echo "$value" | sed 's/\\/\\\\/g')"
|
||||
value=${value//&/"\&"}
|
||||
local first_char="${expression:0:1}"
|
||||
delimiter=$'\001'
|
||||
if [[ "$first_char" == '"' ]]; then
|
||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||
# So we need \\\\ to go through 2 sed
|
||||
value="$(echo "$value" | sed 's/"/\\\\"/g')"
|
||||
sed -ri "${range}s$delimiter"'(^'"${var_part}"'")([^"]|\\")*("[\s;,]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}"'"'"${endline}${delimiter}i" ${file}
|
||||
elif [[ "$first_char" == "'" ]]; then
|
||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||
# However double quotes implies to double \\ to
|
||||
# So we need \\\\\\\\ to go through 2 sed and 1 double quotes str
|
||||
value="$(echo "$value" | sed "s/'/\\\\\\\\'/g")"
|
||||
sed -ri "${range}s$delimiter(^${var_part}')([^']|\\')*('"'[\s,;]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}'${endline}${delimiter}i" ${file}
|
||||
else
|
||||
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] || [[ "$ext" =~ ^php|py|json|js$ ]]; then
|
||||
value='\"'"$(echo "$value" | sed 's/"/\\\\"/g')"'\"'
|
||||
fi
|
||||
if [[ "$ext" =~ ^yaml|yml$ ]]; then
|
||||
value=" $value"
|
||||
fi
|
||||
sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file}
|
||||
fi
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Render templates with Jinja2
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# Attention : Variables should be exported before calling this helper to be
|
||||
# accessible inside templates.
|
||||
#
|
||||
# usage: ynh_render_template some_template output_path
|
||||
# | arg: some_template - Template file to be rendered
|
||||
# | arg: output_path - The path where the output will be redirected to
|
||||
ynh_render_template() {
|
||||
local template_path=$1
|
||||
local output_path=$2
|
||||
mkdir -p "$(dirname $output_path)"
|
||||
# Taken from https://stackoverflow.com/a/35009576
|
||||
python3 -c 'import os, sys, jinja2; sys.stdout.write(
|
||||
jinja2.Template(sys.stdin.read()
|
||||
).render(os.environ));' <$template_path >$output_path
|
||||
}
|
453
helpers/helpers.v1.d/utils
Normal file
453
helpers/helpers.v1.d/utils
Normal file
|
@ -0,0 +1,453 @@
|
|||
#!/bin/bash
|
||||
|
||||
YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
|
||||
|
||||
# Handle script crashes / failures
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage:
|
||||
# ynh_exit_properly is used only by the helper ynh_abort_if_errors.
|
||||
# You should not use it directly.
|
||||
# Instead, add to your script:
|
||||
# ynh_clean_setup () {
|
||||
# instructions...
|
||||
# }
|
||||
#
|
||||
# This function provide a way to clean some residual of installation that not managed by remove script.
|
||||
#
|
||||
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_exit_properly() {
|
||||
local exit_code=$?
|
||||
|
||||
if [[ "${YNH_APP_ACTION:-}" =~ ^install$|^upgrade$|^restore$ ]]
|
||||
then
|
||||
rm -rf "/var/cache/yunohost/download/"
|
||||
fi
|
||||
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
exit 0 # Exit without error if the script ended correctly
|
||||
fi
|
||||
|
||||
trap '' EXIT # Ignore new exit signals
|
||||
# Do not exit anymore if a command fail or if a variable is empty
|
||||
set +o errexit # set +e
|
||||
set +o nounset # set +u
|
||||
|
||||
# Small tempo to avoid the next message being mixed up with other DEBUG messages
|
||||
sleep 0.5
|
||||
|
||||
if type -t ynh_clean_setup >/dev/null; then # Check if the function exist in the app script.
|
||||
ynh_clean_setup # Call the function to do specific cleaning for the app.
|
||||
fi
|
||||
|
||||
# Exit with error status
|
||||
# We don't call ynh_die basically to avoid unecessary 10-ish
|
||||
# debug lines about parsing args and stuff just to exit 1..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Exits if an error occurs during the execution of the script.
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_abort_if_errors
|
||||
#
|
||||
# This configure the rest of the script execution such that, if an error occurs
|
||||
# or if an empty variable is used, the execution of the script stops immediately
|
||||
# and a call to `ynh_clean_setup` is triggered if it has been defined by your script.
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_abort_if_errors() {
|
||||
set -o errexit # set -e; Exit if a command fail
|
||||
set -o nounset # set -u; And if a variable is used unset
|
||||
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
||||
}
|
||||
|
||||
# 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
|
||||
ynh_abort_if_errors
|
||||
fi
|
||||
|
||||
# Curl abstraction to help with POST requests to local pages (such as installation forms)
|
||||
#
|
||||
# usage: ynh_local_curl "page_uri" "key1=value1" "key2=value2" ...
|
||||
# | arg: page_uri - Path (relative to `$path_url`) of the page where POST data will be sent
|
||||
# | arg: key1=value1 - (Optionnal) POST key and corresponding value
|
||||
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
|
||||
# | arg: ... - (Optionnal) More POST keys and values
|
||||
#
|
||||
# example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"
|
||||
#
|
||||
# For multiple calls, cookies are persisted between each call for the same app
|
||||
#
|
||||
# `$domain` and `$path_url` should be defined externally (and correspond to the domain.tld and the /path (of the app?))
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_local_curl() {
|
||||
# Define url of page to curl
|
||||
local local_page=$(ynh_normalize_url_path $1)
|
||||
local full_path=$path_url$local_page
|
||||
|
||||
if [ "${path_url}" == "/" ]; then
|
||||
full_path=$local_page
|
||||
fi
|
||||
|
||||
local full_page_url=https://localhost$full_path
|
||||
|
||||
# Concatenate all other arguments with '&' to prepare POST data
|
||||
local POST_data=""
|
||||
local arg=""
|
||||
for arg in "${@:2}"; do
|
||||
POST_data="${POST_data}${arg}&"
|
||||
done
|
||||
if [ -n "$POST_data" ]; then
|
||||
# Add --data arg and remove the last character, which is an unecessary '&'
|
||||
POST_data="--data ${POST_data::-1}"
|
||||
fi
|
||||
|
||||
# Wait untils nginx has fully reloaded (avoid curl fail with http2)
|
||||
sleep 2
|
||||
|
||||
local cookiefile=/tmp/ynh-$app-cookie.txt
|
||||
touch $cookiefile
|
||||
chown root $cookiefile
|
||||
chmod 700 $cookiefile
|
||||
|
||||
# Temporarily enable visitors if needed...
|
||||
local visitors_enabled=$(ynh_permission_has_user "main" "visitors" && echo yes || echo no)
|
||||
if [[ $visitors_enabled == "no" ]]; then
|
||||
ynh_permission_update --permission "main" --add "visitors"
|
||||
fi
|
||||
|
||||
# Curl the URL
|
||||
curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile
|
||||
|
||||
if [[ $visitors_enabled == "no" ]]; then
|
||||
ynh_permission_update --permission "main" --remove "visitors"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetch the Debian release codename
|
||||
#
|
||||
# [packagingv1]
|
||||
#
|
||||
# usage: ynh_get_debian_release
|
||||
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
|
||||
#
|
||||
# Requires YunoHost version 2.7.12 or higher.
|
||||
ynh_get_debian_release() {
|
||||
echo $(lsb_release --codename --short)
|
||||
}
|
||||
|
||||
_acceptable_path_to_delete() {
|
||||
local file=$1
|
||||
|
||||
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
|
||||
forbidden_paths=$(echo "$forbidden_paths" | grep -v "/home/$app")
|
||||
fi
|
||||
|
||||
# Use realpath to normalize the path ..
|
||||
# i.e convert ///foo//bar//..///baz//// to /foo/baz
|
||||
file=$(realpath --no-symlinks "$file")
|
||||
if [ -z "$file" ] || grep -q -x -F "$file" <<< "$forbidden_paths"; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove a file or a directory securely
|
||||
#
|
||||
# usage: ynh_secure_remove --file=path_to_remove
|
||||
# | arg: -f, --file= - File or directory to remove
|
||||
#
|
||||
# Requires YunoHost version 2.6.4 or higher.
|
||||
ynh_secure_remove() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=f
|
||||
local -A args_array=([f]=file=)
|
||||
local file
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
set +o xtrace # set +x
|
||||
|
||||
if [ $# -ge 2 ]; then
|
||||
ynh_print_warn --message="/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time."
|
||||
fi
|
||||
|
||||
if [[ -z "$file" ]]; then
|
||||
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
|
||||
elif [[ ! -e $file ]]; then
|
||||
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
||||
elif ! _acceptable_path_to_delete "$file"; then
|
||||
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
|
||||
else
|
||||
rm --recursive "$file"
|
||||
fi
|
||||
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Read the value of a key in a ynh manifest file
|
||||
#
|
||||
# usage: ynh_read_manifest --manifest="manifest.json" --manifest_key="key"
|
||||
# | arg: -m, --manifest= - Path of the manifest to read
|
||||
# | arg: -k, --manifest_key= - Name of the key to find
|
||||
# | ret: the value associate to that key
|
||||
#
|
||||
# Requires YunoHost version 3.5.0 or higher.
|
||||
ynh_read_manifest() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=mk
|
||||
local -A args_array=([m]=manifest= [k]=manifest_key=)
|
||||
local manifest
|
||||
local manifest_key
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
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
|
||||
manifest="$YNH_APP_BASEDIR/manifest.json"
|
||||
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
|
||||
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
|
||||
fi
|
||||
}
|
||||
|
||||
# Read the upstream version from the manifest or `$YNH_APP_MANIFEST_VERSION`
|
||||
#
|
||||
# usage: ynh_app_upstream_version [--manifest="manifest.json"]
|
||||
# | arg: -m, --manifest= - Path of the manifest to read
|
||||
# | ret: the version number of the upstream app
|
||||
#
|
||||
# If the `manifest` is not specified, the envvar `$YNH_APP_MANIFEST_VERSION` will be used.
|
||||
#
|
||||
# The version number in the manifest is defined by `<upstreamversion>~ynh<packageversion>`.
|
||||
#
|
||||
# For example, if the manifest contains `4.3-2~ynh3` the function will return `4.3-2`
|
||||
#
|
||||
# Requires YunoHost version 3.5.0 or higher.
|
||||
ynh_app_upstream_version() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=m
|
||||
local -A args_array=([m]=manifest=)
|
||||
local manifest
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
manifest="${manifest:-}"
|
||||
|
||||
if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]]; then
|
||||
version_key_=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
||||
else
|
||||
version_key_=$YNH_APP_MANIFEST_VERSION
|
||||
fi
|
||||
|
||||
echo "${version_key_/~ynh*/}"
|
||||
}
|
||||
|
||||
# Read package version from the manifest
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: ynh_app_package_version [--manifest="manifest.json"]
|
||||
# | arg: -m, --manifest= - Path of the manifest to read
|
||||
# | ret: the version number of the package
|
||||
#
|
||||
# The version number in the manifest is defined by `<upstreamversion>~ynh<packageversion>`.
|
||||
#
|
||||
# For example, if the manifest contains `4.3-2~ynh3` the function will return `3`
|
||||
#
|
||||
# Requires YunoHost version 3.5.0 or higher.
|
||||
ynh_app_package_version() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=m
|
||||
local -A args_array=([m]=manifest=)
|
||||
local manifest
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
version_key_=$YNH_APP_MANIFEST_VERSION
|
||||
echo "${version_key_/*~ynh/}"
|
||||
}
|
||||
|
||||
# Checks the app version to upgrade with the existing app version and returns:
|
||||
#
|
||||
# usage: ynh_check_app_version_changed
|
||||
# | ret: `UPGRADE_APP` if the upstream version changed, `UPGRADE_PACKAGE` otherwise.
|
||||
#
|
||||
# This helper should be used to avoid an upgrade of an app, or the upstream part
|
||||
# of it, when it's not needed
|
||||
#
|
||||
# Requires YunoHost version 3.5.0 or higher.
|
||||
ynh_check_app_version_changed() {
|
||||
local return_value=${YNH_APP_UPGRADE_TYPE}
|
||||
|
||||
if [ "$return_value" == "UPGRADE_SAME" ] || [ "$return_value" == "DOWNGRADE" ]; then
|
||||
return_value="UPGRADE_APP"
|
||||
fi
|
||||
|
||||
echo $return_value
|
||||
}
|
||||
|
||||
# Compare the current package version against another version given as an argument.
|
||||
#
|
||||
# usage: ynh_compare_current_package_version --comparison (lt|le|eq|ne|ge|gt) --version <X~ynhY>
|
||||
# | arg: --comparison - Comparison type. Could be : `lt` (lower than), `le` (lower or equal), `eq` (equal), `ne` (not equal), `ge` (greater or equal), `gt` (greater than)
|
||||
# | arg: --version - The version to compare. Need to be a version in the yunohost package version type (like `2.3.1~ynh4`)
|
||||
# | ret: 0 if the evaluation is true, 1 if false.
|
||||
#
|
||||
# example: ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1
|
||||
#
|
||||
# This helper is usually used when we need to do some actions only for some old package versions.
|
||||
#
|
||||
# Generally you might probably use it as follow in the upgrade script :
|
||||
# ```
|
||||
# if ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1
|
||||
# then
|
||||
# # Do something that is needed for the package version older than 2.3.2~ynh1
|
||||
# fi
|
||||
# ```
|
||||
#
|
||||
# Requires YunoHost version 3.8.0 or higher.
|
||||
ynh_compare_current_package_version() {
|
||||
local legacy_args=cv
|
||||
declare -Ar args_array=([c]=comparison= [v]=version=)
|
||||
local version
|
||||
local comparison
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
local current_version=$YNH_APP_CURRENT_VERSION
|
||||
|
||||
# Check the syntax of the versions
|
||||
if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]]; then
|
||||
ynh_die --message="Invalid argument for version."
|
||||
fi
|
||||
|
||||
# Check validity of the comparator
|
||||
if [[ ! $comparison =~ (lt|le|eq|ne|ge|gt) ]]; then
|
||||
ynh_die --message="Invalid comparator must be : lt, le, eq, ne, ge, gt"
|
||||
fi
|
||||
|
||||
# Return the return value of dpkg --compare-versions
|
||||
dpkg --compare-versions $current_version $comparison $version
|
||||
}
|
||||
|
||||
# Check if we should enforce sane default permissions (= disable rwx for 'others')
|
||||
# on file/folders handled with ynh_setup_source and ynh_add_config
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# Having a file others-readable or a folder others-executable(=enterable)
|
||||
# is a security risk comparable to "chmod 777"
|
||||
#
|
||||
# Configuration files may contain secrets. Or even just being able to enter a
|
||||
# folder may allow an attacker to do nasty stuff (maybe a file or subfolder has
|
||||
# some write permission enabled for 'other' and the attacker may edit the
|
||||
# content or create files as leverage for priviledge escalation ...)
|
||||
#
|
||||
# The sane default should be to set ownership to $app:$app.
|
||||
# In specific case, you may want to set the ownership to $app:www-data
|
||||
# for example if nginx needs access to static files.
|
||||
#
|
||||
_ynh_apply_default_permissions() {
|
||||
local target=$1
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
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'
|
||||
}
|
||||
|
||||
toml_to_json() {
|
||||
python3 -c 'import toml, json, sys; print(json.dumps(toml.load(sys.stdin)))'
|
||||
}
|
||||
|
||||
# Check if a YunoHost user exists
|
||||
#
|
||||
# usage: ynh_user_exists --username=username
|
||||
# | arg: -u, --username= - the username to check
|
||||
# | ret: 0 if the user exists, 1 otherwise.
|
||||
#
|
||||
# example: ynh_user_exists 'toto' || echo "User does not exist"
|
||||
#
|
||||
# Requires YunoHost version 2.2.4 or higher.
|
||||
ynh_user_exists() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=u
|
||||
local -A args_array=([u]=username=)
|
||||
local username
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
yunohost user list --output-as json --quiet | jq -e ".users.\"${username}\"" >/dev/null
|
||||
}
|
||||
|
||||
# Retrieve a YunoHost user information
|
||||
#
|
||||
# usage: ynh_user_get_info --username=username --key=key
|
||||
# | arg: -u, --username= - the username to retrieve info from
|
||||
# | arg: -k, --key= - the key to retrieve
|
||||
# | ret: the value associate to that key
|
||||
#
|
||||
# example: mail=$(ynh_user_get_info --username="toto" --key=mail)
|
||||
#
|
||||
# Requires YunoHost version 2.2.4 or higher.
|
||||
ynh_user_get_info() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=uk
|
||||
local -A args_array=([u]=username= [k]=key=)
|
||||
local username
|
||||
local key
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
yunohost user info "$username" --output-as json --quiet | jq -r ".$key"
|
||||
}
|
||||
|
||||
# Get the list of YunoHost users
|
||||
#
|
||||
# usage: ynh_user_list
|
||||
# | ret: one username per line as strings
|
||||
#
|
||||
# example: for u in $(ynh_user_list); do ... ; done
|
||||
#
|
||||
# Requires YunoHost version 2.4.0 or higher.
|
||||
ynh_user_list() {
|
||||
yunohost user list --output-as json --quiet | jq -r ".users | keys[]"
|
||||
}
|
1
helpers/helpers.v1.d/vendor
Symbolic link
1
helpers/helpers.v1.d/vendor
Symbolic link
|
@ -0,0 +1 @@
|
|||
../vendor
|
336
helpers/helpers.v2.1.d/apt
Normal file
336
helpers/helpers.v2.1.d/apt
Normal file
|
@ -0,0 +1,336 @@
|
|||
#!/bin/bash
|
||||
|
||||
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"
|
||||
#
|
||||
# usage: ynh_install_app_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).
|
||||
#
|
||||
ynh_apt_install_dependencies() {
|
||||
|
||||
# Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below)
|
||||
local dependencies="$(sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g' <<< "$@" | sed 's/|/ | /')"
|
||||
local version=$(ynh_read_manifest "version")
|
||||
local app_ynh_deps="${app//_/-}-ynh-deps" # Replace all '_' by '-', and append -ynh-deps
|
||||
|
||||
# Handle specific versions
|
||||
if grep '[<=>]' <<< "$dependencies"; then
|
||||
# Replace version specifications by relationships syntax
|
||||
# https://www.debian.org/doc/debian-policy/ch-relationships.html
|
||||
# Sed clarification
|
||||
# [^(\<=\>] ignore if it begins by ( or < = >. To not apply twice.
|
||||
# [\<=\>] matches < = or >
|
||||
# \+ matches one or more occurence of the previous characters, for >= or >>.
|
||||
# [^,]\+ matches all characters except ','
|
||||
# Ex: 'package>=1.0' will be replaced by 'package (>= 1.0)'
|
||||
dependencies="$(sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g' <<< "$dependencies")"
|
||||
fi
|
||||
|
||||
# ############################## #
|
||||
# Specific tweaks related to PHP #
|
||||
# ############################## #
|
||||
|
||||
# Check for specific php dependencies which requires sury
|
||||
# This grep will for example return "7.4" if dependencies is "foo bar php7.4-pwet php-gni"
|
||||
# The (?<=php) syntax corresponds to lookbehind ;)
|
||||
local specific_php_version=$(grep -oP '(?<=php)[0-9.]+(?=-|\>|)' <<< "$dependencies" | sort -u)
|
||||
|
||||
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"
|
||||
|
||||
dependencies+=", php${specific_php_version}, php${specific_php_version}-fpm, php${specific_php_version}-common"
|
||||
|
||||
local old_php_version=$(ynh_app_setting_get --key=php_version)
|
||||
|
||||
# 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
|
||||
ynh_backup_if_checksum_is_different "/etc/php/$php_version/fpm/pool.d/$app.conf"
|
||||
ynh_config_remove_phpfpm
|
||||
fi
|
||||
fi
|
||||
# Store php_version into the config of this app
|
||||
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
|
||||
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
||||
fi
|
||||
elif grep --quiet 'php' <<< "$dependencies"; then
|
||||
ynh_app_setting_set --key=php_version --value=$YNH_DEFAULT_PHP_VERSION
|
||||
fi
|
||||
|
||||
# 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
|
||||
# entire control file (This is in particular meant to cover the case of
|
||||
# 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_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
|
||||
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${app_ynh_deps}) "
|
||||
current_dependencies=${current_dependencies// | /|}
|
||||
fi
|
||||
dependencies="$current_dependencies, $dependencies"
|
||||
fi
|
||||
|
||||
# ################
|
||||
# Actual install #
|
||||
# ################
|
||||
|
||||
# Prepare the virtual-dependency control file for dpkg-deb --build
|
||||
local TMPDIR=$(mktemp --directory)
|
||||
mkdir -p ${TMPDIR}/${app_ynh_deps}/DEBIAN
|
||||
# For some reason, dpkg-deb insists for folder perm to be 755 and sometimes it's 777 o_O?
|
||||
chmod -R 755 ${TMPDIR}/${app_ynh_deps}
|
||||
|
||||
cat >${TMPDIR}/${app_ynh_deps}/DEBIAN/control <<EOF
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Package: ${app_ynh_deps}
|
||||
Version: ${version}
|
||||
Depends: ${dependencies}
|
||||
Architecture: all
|
||||
Maintainer: root@localhost
|
||||
Description: Fake package for ${app} (YunoHost app) dependencies
|
||||
This meta-package is only responsible of installing its dependencies.
|
||||
EOF
|
||||
|
||||
_ynh_apt update
|
||||
|
||||
_ynh_wait_dpkg_free
|
||||
|
||||
(
|
||||
# NB: this is in a subshell (though not sure why exactly not just use pushd/popd...)
|
||||
cd "$TMPDIR"
|
||||
# Install the fake package without its dependencies with dpkg --force-depends
|
||||
LC_ALL=C dpkg-deb --build ${app_ynh_deps} ${app_ynh_deps}.deb > ./dpkg_log 2>&1 || { cat ./dpkg_log; false; }
|
||||
LC_ALL=C dpkg --force-depends --install "./${app_ynh_deps}.deb" > ./dpkg_log 2>&1
|
||||
)
|
||||
|
||||
# Then install the missing dependencies with apt install
|
||||
_ynh_apt_install --fix-broken || {
|
||||
# If the installation failed
|
||||
# (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process)
|
||||
# Parse the list of problematic dependencies from dpkg's log ...
|
||||
# (relevant lines look like: "foo-ynh-deps depends on bar; however:")
|
||||
cat $TMPDIR/dpkg_log
|
||||
local problematic_dependencies="$(grep -oP '(?<=-ynh-deps depends on ).*(?=; however)' $TMPDIR/dpkg_log | tr '\n' ' ')"
|
||||
# Fake an install of those dependencies to see the errors
|
||||
# The sed command here is, Print only from 'Reading state info' to the end.
|
||||
[[ -n "$problematic_dependencies" ]] && _ynh_apt_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2
|
||||
ynh_die "Unable to install apt dependencies"
|
||||
}
|
||||
rm --recursive --force "$TMPDIR" # Remove the temp dir.
|
||||
|
||||
# check if the package is actually installed
|
||||
_ynh_apt_package_is_installed "${app_ynh_deps}" || ynh_die "Unable to install apt dependencies"
|
||||
|
||||
# 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
|
||||
yunohost tools regen-conf postgresql
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# Remove fake package and its dependencies
|
||||
#
|
||||
# Dependencies will removed only if no other package need them.
|
||||
#
|
||||
# usage: ynh_apt_remove_dependencies
|
||||
ynh_apt_remove_dependencies() {
|
||||
local app_ynh_deps="${app//_/-}-ynh-deps" # Replace all '_' by '-', and append -ynh-deps
|
||||
|
||||
local current_dependencies=""
|
||||
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
|
||||
|
||||
# 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
|
||||
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
|
||||
_ynh_apt autoremove --purge ${app_ynh_deps}
|
||||
fi
|
||||
}
|
||||
|
||||
# Install packages from an extra repository properly.
|
||||
#
|
||||
# usage: ynh_apt_install_dependencies_from_extra_repository --repo="repo" --package="dep1 dep2" --key=key_url
|
||||
# | arg: --repo= - Complete url of the extra repository.
|
||||
# | arg: --package= - The packages to install from this extra repository
|
||||
# | arg: --key= - url to get the public key.
|
||||
#
|
||||
ynh_apt_install_dependencies_from_extra_repository() {
|
||||
# ============ Argument parsing =============
|
||||
local -A args_array=([r]=repo= [p]=package= [k]=key=)
|
||||
local repo
|
||||
local package
|
||||
local key
|
||||
ynh_handle_getopts_args "$@"
|
||||
# ===========================================
|
||||
|
||||
# Split the repository into uri, suite and components.
|
||||
IFS=', ' read -r -a repo_parts <<< "$repo"
|
||||
index=0
|
||||
|
||||
# Remove "deb " at the beginning of the repo.
|
||||
if [[ "${repo_parts[0]}" == "deb" ]]; then
|
||||
index=1
|
||||
fi
|
||||
uri="${repo_parts[$index]}" ; index=$((index+1))
|
||||
suite="${repo_parts[$index]}" ; index=$((index+1))
|
||||
|
||||
# Get the components
|
||||
if (( "${#repo_parts[@]}" > 0 )); then
|
||||
component="${repo_parts[*]:$index}"
|
||||
fi
|
||||
|
||||
if [[ "$key" == "trusted=yes" ]]; then
|
||||
trust="[trusted=yes]"
|
||||
else
|
||||
trust=""
|
||||
fi
|
||||
|
||||
# Add the new repo in sources.list.d
|
||||
mkdir --parents "/etc/apt/sources.list.d"
|
||||
echo "deb $trust $uri $suite $component" > "/etc/apt/sources.list.d/$app.list"
|
||||
|
||||
# Pin the new repo with the default priority, so it won't be used for upgrades.
|
||||
# Build $pin from the uri without http and any sub path
|
||||
local pin="${uri#*://}"
|
||||
pin="${pin%%/*}"
|
||||
|
||||
# Pin repository
|
||||
mkdir --parents "/etc/apt/preferences.d"
|
||||
cat << EOF > "/etc/apt/preferences.d/$app"
|
||||
Package: *
|
||||
Pin: origin $pin
|
||||
Pin-Priority: 995
|
||||
EOF
|
||||
|
||||
if [ -n "$key" ] && [[ "$key" != "trusted=yes" ]]; then
|
||||
mkdir --parents "/etc/apt/trusted.gpg.d"
|
||||
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
||||
wget --timeout 900 --quiet "$key" --output-document=- | gpg --dearmor > /etc/apt/trusted.gpg.d/$app.gpg
|
||||
fi
|
||||
|
||||
# Update the list of package with the new repo NB: we use -o
|
||||
# Dir::Etc::sourcelist to only refresh this repo, because
|
||||
# ynh_apt_install_dependencies will also call an ynh_apt update on its own
|
||||
# and it's good to limit unecessary requests ... Here we mainly want to
|
||||
# validate that the url+key is correct before going further
|
||||
_ynh_apt update -o Dir::Etc::sourcelist="/etc/apt/sources.list.d/$app.list"
|
||||
|
||||
# Install requested dependencies from this extra repository.
|
||||
# NB: because of the mechanism with $ynh_apt_install_DEPENDENCIES_REPLACE,
|
||||
# this will usually only *append* to the existing list of dependency, not
|
||||
# replace the existing $app-ynh-deps
|
||||
ynh_apt_install_dependencies "$package"
|
||||
|
||||
# Force to upgrade to the last version...
|
||||
# Without doing apt install, an already installed dep is not upgraded
|
||||
local apps_auto_installed="$(apt-mark showauto $package)"
|
||||
_ynh_apt_install "$package"
|
||||
[ -z "$apps_auto_installed" ] || apt-mark auto $apps_auto_installed
|
||||
|
||||
# Remove this extra repository after packages are installed
|
||||
ynh_safe_rm "/etc/apt/sources.list.d/$app.list"
|
||||
ynh_safe_rm "/etc/apt/preferences.d/$app"
|
||||
ynh_safe_rm "/etc/apt/trusted.gpg.d/$app.gpg"
|
||||
_ynh_apt update
|
||||
}
|
||||
|
||||
# #####################
|
||||
# Internal misc utils #
|
||||
# #####################
|
||||
|
||||
# Check if apt is free to use, or wait, until timeout.
|
||||
_ynh_wait_dpkg_free() {
|
||||
local try
|
||||
set +o xtrace # set +x
|
||||
# With seq 1 17, timeout will be almost 30 minutes
|
||||
for try in $(seq 1 17); do
|
||||
# Check if /var/lib/dpkg/lock is used by another process
|
||||
if lsof /var/lib/dpkg/lock >/dev/null; then
|
||||
echo "apt is already in use..."
|
||||
# Sleep an exponential time at each round
|
||||
sleep $((try * try))
|
||||
else
|
||||
# Check if dpkg hasn't been interrupted and is fully available.
|
||||
# See this for more information: https://sources.debian.org/src/apt/1.4.9/apt-pkg/deb/debsystem.cc/#L141-L174
|
||||
local dpkg_dir="/var/lib/dpkg/updates/"
|
||||
|
||||
# For each file in $dpkg_dir
|
||||
while read dpkg_file <&9; do
|
||||
# Check if the name of this file contains only numbers.
|
||||
if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$"; then
|
||||
# If so, that a remaining of dpkg.
|
||||
ynh_print_warn "dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
|
||||
set -o xtrace # set -x
|
||||
return 1
|
||||
fi
|
||||
done 9<<<"$(ls -1 $dpkg_dir)"
|
||||
set -o xtrace # set -x
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo "apt still used, but timeout reached !"
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Check either a package is installed or not
|
||||
_ynh_apt_package_is_installed() {
|
||||
local package=$1
|
||||
dpkg-query --show --showformat='${db:Status-Status}' "$package" 2>/dev/null \
|
||||
| grep --quiet "^installed$" &>/dev/null
|
||||
}
|
||||
|
||||
# Return the installed version of an apt package, if installed
|
||||
_ynh_apt_package_version() {
|
||||
if _ynh_apt_package_is_installed "$package"; then
|
||||
dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null
|
||||
else
|
||||
echo ''
|
||||
fi
|
||||
}
|
||||
|
||||
# APT wrapper for non-interactive operation
|
||||
_ynh_apt() {
|
||||
_ynh_wait_dpkg_free
|
||||
LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get --assume-yes --quiet -o=Acquire::Retries=3 -o=Dpkg::Use-Pty=0 $@
|
||||
}
|
||||
|
||||
# Wrapper around "apt install" with the appropriate options
|
||||
_ynh_apt_install() {
|
||||
_ynh_apt --no-remove --option Dpkg::Options::=--force-confdef \
|
||||
--option Dpkg::Options::=--force-confold install $@
|
||||
}
|
277
helpers/helpers.v2.1.d/backup
Normal file
277
helpers/helpers.v2.1.d/backup
Normal file
|
@ -0,0 +1,277 @@
|
|||
#!/bin/bash
|
||||
|
||||
CAN_BIND=${CAN_BIND:-1}
|
||||
|
||||
# Add a file or a directory to the list of paths to backup
|
||||
#
|
||||
# usage: ynh_backup /path/to/stuff
|
||||
#
|
||||
# NB : note that this helper does *NOT* perform any copy in itself, it only
|
||||
# declares stuff to be backuped via a CSV which is later picked up by the core
|
||||
#
|
||||
# NB 2 : there is a specific behavior for $data_dir (or childs of $data_dir) and
|
||||
# /var/log/$app which are *NOT* backedup during safety-backup-before-upgrade,
|
||||
# OR if the setting "do_not_backup_data" is equals 1 for that app
|
||||
#
|
||||
# The rationale is that these directories are usually too heavy to be integrated in every backup
|
||||
# (think for example about Nextcloud with quite a lot of data, or an app with a lot of media files...)
|
||||
#
|
||||
# This is coupled to the fact that $data_dir and the log dir won't be (and
|
||||
# should NOT) be deleted during remove, unless --purge is used. Hence, if the
|
||||
# upgrade fails and the script is removed prior to restoring the backup, the
|
||||
# data/logs are not destroyed.
|
||||
#
|
||||
ynh_backup() {
|
||||
|
||||
local target="$1"
|
||||
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
|
||||
is_data=true
|
||||
fi
|
||||
|
||||
if [[ -n "${app:-}" ]]
|
||||
then
|
||||
local do_not_backup_data=$(ynh_app_setting_get --key=do_not_backup_data)
|
||||
fi
|
||||
|
||||
# If backing up core only (used by ynh_backup_before_upgrade),
|
||||
# don't backup big data items
|
||||
if [[ "$is_data" == true ]] && ([[ ${do_not_backup_data:-0} -eq 1 ]] || [[ ${BACKUP_CORE_ONLY:-0} -eq 1 ]]); then
|
||||
if [ $BACKUP_CORE_ONLY -eq 1 ]; then
|
||||
ynh_print_info "$target will not be saved, because 'BACKUP_CORE_ONLY' is set."
|
||||
else
|
||||
ynh_print_info "$target will not be saved, because 'do_not_backup_data' is set."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ==============================================================================
|
||||
# Format correctly source and destination paths
|
||||
# ==============================================================================
|
||||
# Be sure the source path is not empty
|
||||
if [ ! -e "$target" ]; then
|
||||
ynh_print_warn "File or folder '${target}' to be backed up does not exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Transform the source path as an absolute path
|
||||
# If it's a dir remove the ending /
|
||||
src_path=$(realpath "$target")
|
||||
|
||||
# Initialize the dest path with the source path relative to "/".
|
||||
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
|
||||
dest_path="${src_path#/}"
|
||||
|
||||
# Check if dest_path already exists in tmp archive
|
||||
if [[ -e "${dest_path}" ]]; then
|
||||
ynh_print_warn "Destination path '${dest_path}' already exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Add the relative current working directory to the destination path
|
||||
local rel_dir="${YNH_CWD#$YNH_BACKUP_DIR}"
|
||||
rel_dir="${rel_dir%/}/"
|
||||
dest_path="${rel_dir}${dest_path}"
|
||||
dest_path="${dest_path#/}"
|
||||
# ==============================================================================
|
||||
|
||||
# ==============================================================================
|
||||
# Write file to backup into backup_list
|
||||
# ==============================================================================
|
||||
local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||
local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||
echo "\"${src}\",\"${dest}\"" >>"${YNH_BACKUP_CSV}"
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
# Create the parent dir of the destination path
|
||||
# It's for retro compatibility, some script consider ynh_backup creates this dir
|
||||
mkdir --parents $(dirname "$YNH_BACKUP_DIR/${dest_path}")
|
||||
}
|
||||
|
||||
# Return the path in the archive where has been stocked the origin path
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# usage: _get_archive_path ORIGIN_PATH
|
||||
_get_archive_path() {
|
||||
# For security reasons we use csv python library to read the CSV
|
||||
python3 -c "
|
||||
import sys
|
||||
import csv
|
||||
with open(sys.argv[1], 'r') as backup_file:
|
||||
backup_csv = csv.DictReader(backup_file, fieldnames=['source', 'dest'])
|
||||
for row in backup_csv:
|
||||
if row['source']==sys.argv[2].strip('\"'):
|
||||
print(row['dest'])
|
||||
sys.exit(0)
|
||||
raise Exception('Original path for %s not found' % sys.argv[2])
|
||||
" "${YNH_BACKUP_CSV}" "$1"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Restore a file or a directory from the backup archive
|
||||
#
|
||||
# usage: ynh_restore /path/to/stuff
|
||||
#
|
||||
# examples:
|
||||
# ynh_restore "/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||
#
|
||||
# If the file or dir to be restored already exists on the system and is lighter
|
||||
# than 500 Mo, it is backed up in `/var/cache/yunohost/appconfbackup/`.
|
||||
# Otherwise, the existing file or dir is removed.
|
||||
#
|
||||
# if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into
|
||||
# `/etc/nginx/conf.d/$domain.d/$app.conf`
|
||||
# otheriwse, search for a match in the csv (eg: conf/nginx.conf) and restore it into
|
||||
# `/etc/nginx/conf.d/$domain.d/$app.conf`
|
||||
ynh_restore() {
|
||||
target="$1"
|
||||
|
||||
local archive_path="$YNH_CWD${target}"
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
else
|
||||
# (get_archive_path will raise an exception if no match found)
|
||||
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$target\")"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Move the old directory if it already exists
|
||||
if [[ -e "${target}" ]]; then
|
||||
# Check if the file/dir size is less than 500 Mo
|
||||
if [[ $(du --summarize --bytes ${target} | cut --delimiter="/" --fields=1) -le "500000000" ]]; then
|
||||
local backup_file="/var/cache/yunohost/appconfbackup/${target}.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||
mkdir --parents "$(dirname "$backup_file")"
|
||||
mv "${target}" "$backup_file" # Move the current file or directory
|
||||
else
|
||||
ynh_safe_rm "${target}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restore target into target
|
||||
mkdir --parents $(dirname "$target")
|
||||
|
||||
# Do a copy if it's just a mounting point
|
||||
if mountpoint --quiet $YNH_BACKUP_DIR; then
|
||||
if [[ -d "${archive_path}" ]]; then
|
||||
archive_path="${archive_path}/."
|
||||
mkdir --parents "$target"
|
||||
fi
|
||||
cp --archive "$archive_path" "${target}"
|
||||
# Do a move if YNH_BACKUP_DIR is already a copy
|
||||
else
|
||||
mv "$archive_path" "${target}"
|
||||
fi
|
||||
|
||||
_ynh_apply_default_permissions "$target"
|
||||
}
|
||||
|
||||
# Restore all files that were previously backuped in an app backup script
|
||||
#
|
||||
# usage: ynh_restore_everything
|
||||
ynh_restore_everything() {
|
||||
# Deduce the relative path of $YNH_CWD
|
||||
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
|
||||
REL_DIR="${REL_DIR%/}/"
|
||||
|
||||
# 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.*(?=\"$)")
|
||||
ynh_restore "$ARCHIVE_PATH"
|
||||
done
|
||||
}
|
||||
|
||||
_ynh_file_checksum_exists() {
|
||||
local file=$1
|
||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||
[[ -n "$(ynh_app_setting_get --key=$checksum_setting_name)" ]]
|
||||
}
|
||||
|
||||
# Calculate and store a file checksum into the app settings
|
||||
#
|
||||
# usage: ynh_store_file_checksum /path/to/file
|
||||
ynh_store_file_checksum() {
|
||||
set +o xtrace # set +x
|
||||
local file=$1
|
||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||
|
||||
ynh_app_setting_set --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
||||
|
||||
if ynh_in_ci_tests; then
|
||||
# Using a base64 is in fact more reversible than "replace / and space by _" ... So we can in fact obtain the original file path in an easy reliable way ...
|
||||
local file_path_base64=$(echo "$file" | base64 -w0)
|
||||
mkdir -p /var/cache/yunohost/appconfbackup/
|
||||
cat $file > /var/cache/yunohost/appconfbackup/original_${file_path_base64}
|
||||
fi
|
||||
|
||||
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
||||
if [ -n "${backup_file_checksum-}" ]; then
|
||||
# Print the diff between the previous file and the new one.
|
||||
# diff return 1 if the files are different, so the || true
|
||||
diff --report-identical-files --unified --color=always $backup_file_checksum $file >&2 || true
|
||||
fi
|
||||
# Unset the variable, so it wouldn't trig a ynh_store_file_checksum without a ynh_backup_if_checksum_is_different before it.
|
||||
unset backup_file_checksum
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Verify the checksum and backup the file if it's different
|
||||
#
|
||||
# usage: ynh_backup_if_checksum_is_different /path/to/file
|
||||
#
|
||||
# This helper is primarily meant to allow to easily backup personalised/manually
|
||||
# modified config files.
|
||||
ynh_backup_if_checksum_is_different() {
|
||||
set +o xtrace # set +x
|
||||
local file=$1
|
||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||
local checksum_value=$(ynh_app_setting_get --key=$checksum_setting_name)
|
||||
# backup_file_checksum isn't declare as local, so it can be reuse by ynh_store_file_checksum
|
||||
backup_file_checksum=""
|
||||
if [ -n "$checksum_value" ]; then # Proceed only if a value was stored into the app settings
|
||||
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status; then # If the checksum is now different
|
||||
|
||||
backup_file_checksum="/var/cache/yunohost/appconfbackup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||
mkdir --parents "$(dirname "$backup_file_checksum")"
|
||||
cp --archive "$file" "$backup_file_checksum" # Backup the current file
|
||||
ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum"
|
||||
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
|
||||
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
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
set -o xtrace # set -x
|
||||
}
|
||||
|
||||
# Delete a file checksum from the app settings
|
||||
#
|
||||
# usage: ynh_delete_file_checksum /path/to/file
|
||||
ynh_delete_file_checksum() {
|
||||
local file=$1
|
||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||
ynh_app_setting_delete --key=$checksum_setting_name
|
||||
}
|
45
helpers/helpers.v2.1.d/composer
Normal file
45
helpers/helpers.v2.1.d/composer
Normal file
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install and initialize Composer in the given directory
|
||||
#
|
||||
# The installed version is defined by `$composer_version` which should be defined
|
||||
# as global prior to calling this helper.
|
||||
#
|
||||
# Will use `$install_dir` as workdir unless `$composer_workdir` exists (but that shouldnt be necessary)
|
||||
#
|
||||
# usage: ynh_composer_install
|
||||
ynh_composer_install() {
|
||||
local workdir="${composer_workdir:-$install_dir}"
|
||||
|
||||
[[ -n "${composer_version}" ]] || ynh_die "\$composer_version should be defined before calling ynh_composer_install. (In the past, this was called \$YNH_COMPOSER_VERSION)"
|
||||
|
||||
[[ ! -e "$workdir/composer.phar" ]] || ynh_safe_rm $workdir/composer.phar
|
||||
|
||||
local composer_url="https://getcomposer.org/download/$composer_version/composer.phar"
|
||||
|
||||
# NB. we have to declare the var as local first,
|
||||
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
|
||||
# because local always return 0 ...
|
||||
local out
|
||||
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
||||
out=$(wget --tries 3 --no-dns-cache --timeout 900 --no-verbose --output-document=$workdir/composer.phar $composer_url 2>&1) \
|
||||
|| ynh_die "$out"
|
||||
}
|
||||
|
||||
# Execute a command with Composer
|
||||
#
|
||||
# Will use `$install_dir` as workdir unless `$composer_workdir` exists (but that shouldnt be necessary)
|
||||
#
|
||||
# You may also define `composer_user=root` prior to call this helper if you
|
||||
# absolutely need composer to run as root, but this is discouraged...
|
||||
#
|
||||
# usage: ynh_composer_exec commands
|
||||
ynh_composer_exec() {
|
||||
local workdir="${composer_workdir:-$install_dir}"
|
||||
|
||||
COMPOSER_HOME="$workdir/.composer" \
|
||||
COMPOSER_MEMORY_LIMIT=-1 \
|
||||
sudo -E -u "${composer_user:-$app}" \
|
||||
php${php_version} "$workdir/composer.phar" $@ \
|
||||
-d "$workdir" --no-interaction --no-ansi 2>&1
|
||||
}
|
363
helpers/helpers.v2.1.d/config
Normal file
363
helpers/helpers.v2.1.d/config
Normal file
|
@ -0,0 +1,363 @@
|
|||
#!/bin/bash
|
||||
|
||||
_ynh_app_config_get_one() {
|
||||
local short_setting="$1"
|
||||
local type="$2"
|
||||
local bind="$3"
|
||||
local getter="get__${short_setting}"
|
||||
# Get value from getter if exists
|
||||
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
old[$short_setting]="$($getter)"
|
||||
formats[${short_setting}]="yaml"
|
||||
|
||||
elif [[ "$bind" == *"("* ]] && type -t "get__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
old[$short_setting]="$("get__${bind%%(*}" $short_setting $type $bind)"
|
||||
formats[${short_setting}]="yaml"
|
||||
|
||||
elif [[ "$bind" == "null" ]]; then
|
||||
old[$short_setting]="YNH_NULL"
|
||||
|
||||
# Get value from app settings or from another file
|
||||
elif [[ "$type" == "file" ]]; then
|
||||
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)"
|
||||
file_hash[$short_setting]="true"
|
||||
|
||||
# Get multiline text from settings or from a full file
|
||||
elif [[ "$type" == "text" ]]; then
|
||||
if [[ "$bind" == "settings" ]]; then
|
||||
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
|
||||
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)"
|
||||
fi
|
||||
|
||||
# Get value from a kind of key/value file
|
||||
else
|
||||
local bind_after=""
|
||||
if [[ "$bind" == "settings" ]]; then
|
||||
bind=":/etc/yunohost/apps/$app/settings.yml"
|
||||
fi
|
||||
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||
bind_key_=${bind_key_:-$short_setting}
|
||||
if [[ "$bind_key_" == *">"* ]]; then
|
||||
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/)"
|
||||
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
|
||||
|
||||
fi
|
||||
}
|
||||
_ynh_app_config_apply_one() {
|
||||
local short_setting="$1"
|
||||
local setter="set__${short_setting}"
|
||||
local bind="${binds[$short_setting]}"
|
||||
local type="${types[$short_setting]}"
|
||||
if [ "${changed[$short_setting]}" == "true" ]; then
|
||||
# Apply setter if exists
|
||||
if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
$setter
|
||||
|
||||
elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
"set__${bind%%(*}" $short_setting $type $bind
|
||||
|
||||
elif [[ "$bind" == "null" ]]; then
|
||||
return
|
||||
|
||||
# Save in a file
|
||||
elif [[ "$type" == "file" ]]; then
|
||||
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/)"
|
||||
if [[ "${!short_setting}" == "" ]]; then
|
||||
ynh_backup_if_checksum_is_different "$bind_file"
|
||||
ynh_safe_rm "$bind_file"
|
||||
ynh_delete_file_checksum "$bind_file"
|
||||
ynh_print_info "File '$bind_file' removed"
|
||||
else
|
||||
ynh_backup_if_checksum_is_different "$bind_file"
|
||||
if [[ "${!short_setting}" != "$bind_file" ]]; then
|
||||
cp "${!short_setting}" "$bind_file"
|
||||
fi
|
||||
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}"
|
||||
fi
|
||||
|
||||
# Save value in app settings
|
||||
elif [[ "$bind" == "settings" ]]; then
|
||||
ynh_app_setting_set --key=$short_setting --value="${!short_setting}"
|
||||
ynh_print_info "Configuration key '$short_setting' edited in app settings"
|
||||
|
||||
# Save multiline text in a file
|
||||
elif [[ "$type" == "text" ]]; then
|
||||
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/)"
|
||||
ynh_backup_if_checksum_is_different "$bind_file"
|
||||
echo "${!short_setting}" >"$bind_file"
|
||||
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}'"
|
||||
|
||||
# Set value into a kind of key/value file
|
||||
else
|
||||
local bind_after=""
|
||||
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||
if [[ "$bind_key_" == *">"* ]]; then
|
||||
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
||||
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/)"
|
||||
|
||||
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
|
||||
ynh_store_file_checksum "$bind_file"
|
||||
fi
|
||||
|
||||
# We stored the info in settings in order to be able to upgrade the app
|
||||
ynh_app_setting_set --key=$short_setting --value="${!short_setting}"
|
||||
ynh_print_info "Configuration key '$bind_key_' edited into $bind_file"
|
||||
|
||||
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
|
||||
# Split line into short_setting, type and bind
|
||||
IFS='|' read short_setting type bind <<<"$line"
|
||||
binds[${short_setting}]="$bind"
|
||||
types[${short_setting}]="$type"
|
||||
file_hash[${short_setting}]=""
|
||||
formats[${short_setting}]=""
|
||||
ynh_app_config_get_one $short_setting $type $bind
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
_ynh_app_config_apply() {
|
||||
for short_setting in "${!old[@]}"; do
|
||||
ynh_app_config_apply_one $short_setting
|
||||
done
|
||||
}
|
||||
|
||||
_ynh_app_config_show() {
|
||||
for short_setting in "${!old[@]}"; do
|
||||
if [[ "${old[$short_setting]}" != YNH_NULL ]]; then
|
||||
if [[ "${formats[$short_setting]}" == "yaml" ]]; then
|
||||
ynh_return "${short_setting}:"
|
||||
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
||||
else
|
||||
ynh_return "${short_setting}: '$(echo "${old[$short_setting]}" | sed "s/'/''/g" | sed ':a;N;$!ba;s/\n/\n\n/g')'"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_ynh_app_config_validate() {
|
||||
# Change detection
|
||||
ynh_script_progression "Checking what changed in the new configuration..."
|
||||
local nothing_changed=true
|
||||
local changes_validated=true
|
||||
for short_setting in "${!old[@]}"; do
|
||||
changed[$short_setting]=false
|
||||
if [ -z ${!short_setting+x} ]; then
|
||||
# Assign the var with the old value in order to allows multiple
|
||||
# args validation
|
||||
declare -g "$short_setting"="${old[$short_setting]}"
|
||||
continue
|
||||
fi
|
||||
if [ ! -z "${file_hash[${short_setting}]}" ]; then
|
||||
file_hash[old__$short_setting]=""
|
||||
file_hash[new__$short_setting]=""
|
||||
if [ -f "${old[$short_setting]}" ]; then
|
||||
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
|
||||
if [ -z "${!short_setting}" ]; then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
if [ -f "${!short_setting}" ]; then
|
||||
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
|
||||
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]; then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]; then
|
||||
changed[$short_setting]=true
|
||||
nothing_changed=false
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ "$nothing_changed" == "true" ]]; then
|
||||
ynh_print_info "Nothing has changed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run validation if something is changed
|
||||
ynh_script_progression "Validating the new configuration..."
|
||||
|
||||
for short_setting in "${!old[@]}"; do
|
||||
[[ "${changed[$short_setting]}" == "false" ]] && continue
|
||||
local result=""
|
||||
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
|
||||
result="$(validate__$short_setting)"
|
||||
elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
"validate__${bind%%(*}" $short_setting
|
||||
fi
|
||||
if [ -n "$result" ]; then
|
||||
#
|
||||
# Return a yaml such as:
|
||||
#
|
||||
# validation_errors:
|
||||
# some_key: "An error message"
|
||||
# some_other_key: "Another error message"
|
||||
#
|
||||
# We use changes_validated to know if this is
|
||||
# the first validation error
|
||||
if [[ "$changes_validated" == true ]]; then
|
||||
ynh_return "validation_errors:"
|
||||
fi
|
||||
ynh_return " ${short_setting}: \"$result\""
|
||||
changes_validated=false
|
||||
fi
|
||||
done
|
||||
|
||||
# If validation failed, exit the script right now (instead of going into apply)
|
||||
# Yunohost core will pick up the errors returned via ynh_return previously
|
||||
if [[ "$changes_validated" == "false" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
ynh_app_config_get_one() {
|
||||
_ynh_app_config_get_one $1 $2 $3
|
||||
}
|
||||
|
||||
ynh_app_config_get() {
|
||||
_ynh_app_config_get
|
||||
}
|
||||
|
||||
ynh_app_config_show() {
|
||||
_ynh_app_config_show
|
||||
}
|
||||
|
||||
ynh_app_config_validate() {
|
||||
_ynh_app_config_validate
|
||||
}
|
||||
|
||||
ynh_app_config_apply_one() {
|
||||
_ynh_app_config_apply_one $1
|
||||
}
|
||||
ynh_app_config_apply() {
|
||||
_ynh_app_config_apply
|
||||
}
|
||||
|
||||
ynh_app_action_run() {
|
||||
local runner="run__$1"
|
||||
# Get value from getter if exists
|
||||
if type -t "$runner" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||
$runner
|
||||
#ynh_return "result:"
|
||||
#ynh_return "$(echo "${result}" | sed 's/^/ /g')"
|
||||
else
|
||||
ynh_die "No handler defined in app's script for action $1. If you are the maintainer of this app, you should define '$runner'"
|
||||
fi
|
||||
}
|
||||
|
||||
ynh_app_config_run() {
|
||||
declare -Ag old=()
|
||||
declare -Ag changed=()
|
||||
declare -Ag file_hash=()
|
||||
declare -Ag binds=()
|
||||
declare -Ag types=()
|
||||
declare -Ag formats=()
|
||||
|
||||
case $1 in
|
||||
show)
|
||||
ynh_app_config_get
|
||||
ynh_app_config_show
|
||||
;;
|
||||
apply)
|
||||
max_progression=4
|
||||
ynh_script_progression "Reading config panel description and current configuration..."
|
||||
ynh_app_config_get
|
||||
|
||||
ynh_app_config_validate
|
||||
|
||||
ynh_script_progression "Applying the new configuration..."
|
||||
ynh_app_config_apply
|
||||
ynh_script_progression "Configuration of $app completed"
|
||||
;;
|
||||
*)
|
||||
ynh_app_action_run $1
|
||||
esac
|
||||
}
|
118
helpers/helpers.v2.1.d/fail2ban
Normal file
118
helpers/helpers.v2.1.d/fail2ban
Normal file
|
@ -0,0 +1,118 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Create a dedicated fail2ban config (jail and filter conf files)
|
||||
#
|
||||
# usage: ynh_config_add_fail2ban --logpath=log_file --failregex=filter
|
||||
# | arg: --logpath= - Log file to be checked by fail2ban
|
||||
# | arg: --failregex= - Failregex to be looked for by fail2ban
|
||||
#
|
||||
# If --logpath / --failregex are provided, the helper will generate the appropriate conf using these.
|
||||
#
|
||||
# Otherwise, it will assume that the app provided templates, namely
|
||||
# `../conf/f2b_jail.conf` and `../conf/f2b_filter.conf`
|
||||
#
|
||||
# They will typically look like (for example here for synapse):
|
||||
# ```
|
||||
# f2b_jail.conf:
|
||||
# [__APP__]
|
||||
# enabled = true
|
||||
# port = http,https
|
||||
# filter = __APP__
|
||||
# logpath = /var/log/__APP__/logfile.log
|
||||
# maxretry = 5
|
||||
# ```
|
||||
# ```
|
||||
# f2b_filter.conf:
|
||||
# [INCLUDES]
|
||||
# before = common.conf
|
||||
# [Definition]
|
||||
#
|
||||
# # Part of regex definition (just used to make more easy to make the global regex)
|
||||
# __synapse_start_line = .? \- synapse\..+ \-
|
||||
#
|
||||
# # Regex definition.
|
||||
# failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- <HOST> \- \d+ \- Received request\: POST /_matrix/client/r0/login\??<SKIPLINES>%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'<SKIPLINES>%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$
|
||||
#
|
||||
# ignoreregex =
|
||||
# ```
|
||||
#
|
||||
# ##### Regarding the the `failregex` option:
|
||||
#
|
||||
# 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\-.^_]+)`
|
||||
#
|
||||
# You can find some more explainations about how to make a regex here :
|
||||
# https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters
|
||||
#
|
||||
# To validate your regex you can test with this command:
|
||||
# ```
|
||||
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
|
||||
# ```
|
||||
ynh_config_add_fail2ban() {
|
||||
# ============ Argument parsing =============
|
||||
local -A args_array=([l]=logpath= [r]=failregex=)
|
||||
local logpath
|
||||
local failregex
|
||||
ynh_handle_getopts_args "$@"
|
||||
# ===========================================
|
||||
|
||||
# If failregex is provided, Build a config file on-the-fly using $logpath and $failregex
|
||||
if [[ -n "${failregex:-}" ]]; then
|
||||
test -n "$logpath" || ynh_die "ynh_config_add_fail2ban expects a logfile path as first argument and received nothing."
|
||||
|
||||
echo "
|
||||
[__APP__]
|
||||
enabled = true
|
||||
port = http,https
|
||||
filter = __APP__
|
||||
logpath = __LOGPATH__
|
||||
maxretry = 5
|
||||
" >"$YNH_APP_BASEDIR/conf/f2b_jail.conf"
|
||||
|
||||
echo "
|
||||
[INCLUDES]
|
||||
before = common.conf
|
||||
[Definition]
|
||||
failregex = __FAILREGEX__
|
||||
ignoreregex =
|
||||
" >"$YNH_APP_BASEDIR/conf/f2b_filter.conf"
|
||||
fi
|
||||
|
||||
ynh_config_add --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
|
||||
ynh_config_add --template="f2b_filter.conf" --destination="/etc/fail2ban/filter.d/$app.conf"
|
||||
|
||||
# if "$logpath" doesn't exist (as if using --use_template argument), assign
|
||||
# "$logpath" using the one in the previously generated fail2ban conf file
|
||||
if [ -z "${logpath:-}" ]; then
|
||||
# the first sed deletes possibles spaces and the second one extract the path
|
||||
logpath=$(grep "^logpath" "/etc/fail2ban/jail.d/$app.conf" | sed "s/ //g" | sed "s/logpath=//g")
|
||||
fi
|
||||
|
||||
# Create the folder and logfile if they doesn't exist,
|
||||
# as fail2ban require an existing logfile before configuration
|
||||
mkdir -p "/var/log/$app"
|
||||
if [ ! -f "$logpath" ]; then
|
||||
touch "$logpath"
|
||||
fi
|
||||
# Make sure log folder's permissions are correct
|
||||
chown -R "$app:$app" "/var/log/$app"
|
||||
chmod -R u=rwX,g=rX,o= "/var/log/$app"
|
||||
|
||||
ynh_systemctl --service=fail2ban --action=reload --wait_until="(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
|
||||
ynh_print_warn "Fail2ban failed to load the jail for $app"
|
||||
ynh_print_warn "${fail2ban_error#*WARNING}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove the dedicated fail2ban config (jail and filter conf files)
|
||||
#
|
||||
# usage: ynh_config_remove_fail2ban
|
||||
ynh_config_remove_fail2ban() {
|
||||
ynh_safe_rm "/etc/fail2ban/jail.d/$app.conf"
|
||||
ynh_safe_rm "/etc/fail2ban/filter.d/$app.conf"
|
||||
ynh_systemctl --service=fail2ban --action=reload
|
||||
}
|
187
helpers/helpers.v2.1.d/getopts
Normal file
187
helpers/helpers.v2.1.d/getopts
Normal file
|
@ -0,0 +1,187 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Internal helper design to allow helpers to use getopts to manage their arguments
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# example: function my_helper()
|
||||
# {
|
||||
# local -A args_array=( [a]=arg1= [b]=arg2= [c]=arg3 )
|
||||
# local arg1
|
||||
# local arg2
|
||||
# local arg3
|
||||
# ynh_handle_getopts_args "$@"
|
||||
#
|
||||
# [...]
|
||||
# }
|
||||
# my_helper --arg1 "val1" -b val2 -c
|
||||
#
|
||||
# usage: ynh_handle_getopts_args "$@"
|
||||
# | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function
|
||||
#
|
||||
# This helper need an array, named "args_array" with all the arguments used by the helper
|
||||
# that want to use ynh_handle_getopts_args
|
||||
# Be carreful, this array has to be an associative array, as the following example:
|
||||
# local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
|
||||
# Let's explain this array:
|
||||
# a, b and c are short options, -a, -b and -c
|
||||
# arg1, arg2 and arg3 are the long options associated to the previous short ones. --arg1, --arg2 and --arg3
|
||||
# For each option, a short and long version has to be defined.
|
||||
# Let's see something more significant
|
||||
# local -A args_array=( [u]=user [f]=finalpath= [d]=database )
|
||||
#
|
||||
# NB: Because we're using 'declare' without -g, the array will be declared as a local variable.
|
||||
#
|
||||
# Please keep in mind that the long option will be used as a variable to store the values for this option.
|
||||
# For the previous example, that means that $finalpath will be fill with the value given as argument for this option.
|
||||
#
|
||||
# Also, in the previous example, finalpath has a '=' at the end. That means this option need a value.
|
||||
# So, the helper has to be call with --finalpath /final/path, --finalpath=/final/path or -f /final/path, the variable $finalpath will get the value /final/path
|
||||
# If there's many values for an option, -f /final /path, the value will be separated by a ';' $finalpath=/final;/path
|
||||
# For an option without value, like --user in the example, the helper can be called only with --user or -u. $user will then get the value 1.
|
||||
#
|
||||
ynh_handle_getopts_args() {
|
||||
# Trick to only re-enable debugging if it was set before
|
||||
local xtrace_enable=$(set +o | grep xtrace)
|
||||
|
||||
# Manage arguments only if there's some provided
|
||||
set +o xtrace # set +x
|
||||
if [ $# -eq 0 ]; then
|
||||
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
|
||||
ynh_die "It looks like you called the helper using positional arguments instead of keyword arguments ?"
|
||||
fi
|
||||
|
||||
# Store arguments in an array to keep each argument separated
|
||||
local arguments=("$@")
|
||||
|
||||
# For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u)
|
||||
# And built parameters string for getopts
|
||||
# ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
|
||||
local getopts_parameters=""
|
||||
local option_flag=""
|
||||
for option_flag in "${!args_array[@]}"; do
|
||||
# Concatenate each option_flags of the array to build the string of arguments for getopts
|
||||
# Will looks like 'abcd' for -a -b -c -d
|
||||
# If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
|
||||
# Check the last character of the value associate to the option_flag
|
||||
if [ "${args_array[$option_flag]: -1}" = "=" ]; then
|
||||
# For an option with additionnal values, add a ':' after the letter for getopts.
|
||||
getopts_parameters="${getopts_parameters}${option_flag}:"
|
||||
else
|
||||
getopts_parameters="${getopts_parameters}${option_flag}"
|
||||
fi
|
||||
# Check each argument given to the function
|
||||
local arg=""
|
||||
# ${#arguments[@]} is the size of the array
|
||||
for arg in $(seq 0 $((${#arguments[@]} - 1))); do
|
||||
# Escape options' values starting with -. Otherwise the - will be considered as another option.
|
||||
arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}"
|
||||
# And replace long option (value of the option_flag) by the short option, the option_flag itself
|
||||
# (e.g. for [u]=user, --user will be -u)
|
||||
# Replace long option with = (match the beginning of the argument)
|
||||
arguments[arg]="$(printf '%s\n' "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]}/-${option_flag} /")"
|
||||
# And long option without = (match the whole line)
|
||||
arguments[arg]="$(printf '%s\n' "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]%=}$/-${option_flag} /")"
|
||||
done
|
||||
done
|
||||
|
||||
# Read and parse all the arguments
|
||||
# Use a function here, to use standart arguments $@ and be able to use shift.
|
||||
parse_arg() {
|
||||
# Read all arguments, until no arguments are left
|
||||
while [ $# -ne 0 ]; do
|
||||
# Initialize the index of getopts
|
||||
OPTIND=1
|
||||
# Parse with getopts only if the argument begin by -, that means the argument is an option
|
||||
# getopts will fill $parameter with the letter of the option it has read.
|
||||
local parameter=""
|
||||
getopts ":$getopts_parameters" parameter || true
|
||||
|
||||
if [ "$parameter" = "?" ]; then
|
||||
ynh_die "Invalid argument: ${1:-}"
|
||||
elif [ "$parameter" = ":" ]; then
|
||||
ynh_die "${1:-} parameter requires an argument."
|
||||
else
|
||||
local shift_value=1
|
||||
# Use the long option, corresponding to the short option read by getopts, as a variable
|
||||
# (e.g. for [u]=user, 'user' will be used as a variable)
|
||||
# Also, remove '=' at the end of the long option
|
||||
# The variable name will be stored in 'option_var'
|
||||
local option_var="${args_array[$parameter]%=}"
|
||||
# If this option doesn't take values
|
||||
# if there's a '=' at the end of the long option name, this option takes values
|
||||
if [ "${args_array[$parameter]: -1}" != "=" ]; then
|
||||
# 'eval ${option_var}' will use the content of 'option_var'
|
||||
eval ${option_var}=1
|
||||
else
|
||||
# Read all other arguments to find multiple value for this option.
|
||||
# Load args in a array
|
||||
local all_args=("$@")
|
||||
|
||||
# If the first argument is longer than 2 characters,
|
||||
# There's a value attached to the option, in the same array cell
|
||||
if [ ${#all_args[0]} -gt 2 ]; then
|
||||
# Remove the option and the space, so keep only the value itself.
|
||||
all_args[0]="${all_args[0]#-${parameter} }"
|
||||
|
||||
# At this point, if all_args[0] start with "-", then the argument is not well formed
|
||||
if [ "${all_args[0]:0:1}" == "-" ]; then
|
||||
ynh_die "Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?"
|
||||
fi
|
||||
# Reduce the value of shift, because the option has been removed manually
|
||||
shift_value=$((shift_value - 1))
|
||||
fi
|
||||
|
||||
# Declare the content of option_var as a variable.
|
||||
eval ${option_var}=""
|
||||
# Then read the array value per value
|
||||
local i
|
||||
for i in $(seq 0 $((${#all_args[@]} - 1))); do
|
||||
# If this argument is an option, end here.
|
||||
if [ "${all_args[$i]:0:1}" == "-" ]; then
|
||||
# Ignore the first value of the array, which is the option itself
|
||||
if [ "$i" -ne 0 ]; then
|
||||
break
|
||||
fi
|
||||
else
|
||||
# Ignore empty parameters
|
||||
if [ -n "${all_args[$i]}" ]; then
|
||||
# Else, add this value to this option
|
||||
# Each value will be separated by ';'
|
||||
if [ -n "${!option_var}" ]; then
|
||||
# If there's already another value for this option, add a ; before adding the new value
|
||||
eval ${option_var}+="\;"
|
||||
fi
|
||||
|
||||
# Remove the \ that escape - at beginning of values.
|
||||
all_args[i]="${all_args[i]//\\TOBEREMOVED\\/}"
|
||||
|
||||
# For the record.
|
||||
# We're using eval here to get the content of the variable stored itself as simple text in $option_var...
|
||||
# Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
|
||||
# But... ${!option_var} can't be used as left part of an assignation.
|
||||
# declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
|
||||
# So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
|
||||
|
||||
eval ${option_var}+='"${all_args[$i]}"'
|
||||
fi
|
||||
shift_value=$((shift_value + 1))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Shift the parameter and its argument(s)
|
||||
shift $shift_value
|
||||
done
|
||||
}
|
||||
|
||||
# Call parse_arg and pass the modified list of args as an array of arguments.
|
||||
parse_arg "${arguments[@]}"
|
||||
|
||||
eval "$xtrace_enable"
|
||||
}
|
195
helpers/helpers.v2.1.d/go
Normal file
195
helpers/helpers.v2.1.d/go
Normal file
|
@ -0,0 +1,195 @@
|
|||
#!/bin/bash
|
||||
|
||||
readonly GOENV_INSTALL_DIR="/opt/goenv"
|
||||
# goenv_ROOT is the directory of goenv, it needs to be loaded as a environment variable.
|
||||
export GOENV_ROOT="$GOENV_INSTALL_DIR"
|
||||
|
||||
_ynh_load_go_in_path_and_other_tweaks() {
|
||||
|
||||
# Get the absolute path of this version of go
|
||||
go_dir="$GOENV_INSTALL_DIR/versions/$app/bin"
|
||||
|
||||
# Load the path of this version of go in $PATH
|
||||
if [[ :$PATH: != *":$go_dir"* ]]; then
|
||||
PATH="$go_dir:$PATH"
|
||||
fi
|
||||
|
||||
# Export PATH such that it's available through sudo -E / ynh_exec_as $app
|
||||
export PATH
|
||||
|
||||
# This is in full lowercase such that it gets replaced in templates
|
||||
path_with_go="$PATH"
|
||||
PATH_with_go="$PATH"
|
||||
|
||||
# Sets the local application-specific go version
|
||||
pushd ${install_dir}
|
||||
$GOENV_INSTALL_DIR/bin/goenv local $go_version
|
||||
popd
|
||||
}
|
||||
|
||||
# Install a specific version of Go using goenv
|
||||
#
|
||||
# The installed version is defined by `$go_version` which should be defined as global prior to calling this helper
|
||||
#
|
||||
# usage: ynh_go_install
|
||||
#
|
||||
# The helper adds the appropriate, specific version of go to the `$PATH` variable (which
|
||||
# is preserved when calling `ynh_exec_as_app`). Also defines:
|
||||
# - `$path_with_go` (the value of the modified `$PATH`, but you dont really need it?)
|
||||
# - `$go_dir` (the directory containing the specific go version)
|
||||
#
|
||||
# This helper also creates a /etc/profile.d/goenv.sh that configures PATH environment for goenv
|
||||
ynh_go_install () {
|
||||
|
||||
[[ -n "${go_version:-}" ]] || ynh_die "\$go_version should be defined prior to calling ynh_go_install"
|
||||
|
||||
# Load goenv path in PATH
|
||||
local CLEAR_PATH="$GOENV_INSTALL_DIR/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Go prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
# Move an existing Go binary, to avoid to block goenv
|
||||
test -x /usr/bin/go && mv /usr/bin/go /usr/bin/go_goenv
|
||||
|
||||
# Install or update goenv
|
||||
mkdir -p $GOENV_INSTALL_DIR
|
||||
pushd "$GOENV_INSTALL_DIR"
|
||||
if ! [ -x "$GOENV_INSTALL_DIR/bin/goenv" ]; then
|
||||
ynh_print_info "Downloading goenv..."
|
||||
git init -q
|
||||
git remote add origin https://github.com/syndbg/goenv.git
|
||||
else
|
||||
ynh_print_info "Updating goenv..."
|
||||
fi
|
||||
git fetch -q --tags --prune origin
|
||||
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||
git checkout -q "$git_latest_tag"
|
||||
_ynh_go_try_bash_extension
|
||||
goenv=$GOENV_INSTALL_DIR/bin/goenv
|
||||
popd
|
||||
|
||||
# Install or update xxenv-latest
|
||||
mkdir -p "$GOENV_INSTALL_DIR/plugins/xxenv-latest"
|
||||
pushd "$GOENV_INSTALL_DIR/plugins/xxenv-latest"
|
||||
if ! [ -x "$GOENV_INSTALL_DIR/plugins/xxenv-latest/bin/goenv-latest" ]; then
|
||||
ynh_print_info "Downloading xxenv-latest..."
|
||||
git init -q
|
||||
git remote add origin https://github.com/momo-lab/xxenv-latest.git
|
||||
else
|
||||
ynh_print_info "Updating xxenv-latest..."
|
||||
fi
|
||||
git fetch -q --tags --prune origin
|
||||
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||
git checkout -q "$git_latest_tag"
|
||||
popd
|
||||
|
||||
# Enable caching
|
||||
mkdir -p "${GOENV_INSTALL_DIR}/cache"
|
||||
|
||||
# Create shims directory if needed
|
||||
mkdir -p "${GOENV_INSTALL_DIR}/shims"
|
||||
|
||||
# Restore /usr/local/bin in PATH
|
||||
PATH=$CLEAR_PATH
|
||||
|
||||
# And replace the old Go binary
|
||||
test -x /usr/bin/go_goenv && mv /usr/bin/go_goenv /usr/bin/go
|
||||
|
||||
# Install the requested version of Go
|
||||
local final_go_version=$("$GOENV_INSTALL_DIR/plugins/xxenv-latest/bin/goenv-latest" --print "$go_version")
|
||||
ynh_print_info "Installation of Go-$final_go_version"
|
||||
goenv install --quiet --skip-existing "$final_go_version" 2>&1
|
||||
|
||||
# Store go_version into the config of this app
|
||||
ynh_app_setting_set --app="$app" --key="go_version" --value="$final_go_version"
|
||||
go_version=$final_go_version
|
||||
|
||||
# Cleanup Go versions
|
||||
_ynh_go_cleanup
|
||||
|
||||
# Set environment for Go users
|
||||
echo "#goenv
|
||||
export GOENV_ROOT=$GOENV_INSTALL_DIR
|
||||
export PATH=\"$GOENV_INSTALL_DIR/bin:$PATH\"
|
||||
eval \"\$(goenv init -)\"
|
||||
#goenv" > /etc/profile.d/goenv.sh
|
||||
|
||||
# Load the environment
|
||||
eval "$(goenv init -)"
|
||||
|
||||
_ynh_load_go_in_path_and_other_tweaks
|
||||
}
|
||||
|
||||
# Remove the version of Go used by the app.
|
||||
#
|
||||
# This helper will also cleanup Go versions
|
||||
#
|
||||
# usage: ynh_go_remove
|
||||
ynh_go_remove () {
|
||||
local go_version=$(ynh_app_setting_get --key="go_version")
|
||||
|
||||
# Load goenv path in PATH
|
||||
local CLEAR_PATH="$GOENV_INSTALL_DIR/bin:$PATH"
|
||||
|
||||
# Remove /usr/local/bin in PATH in case of Go prior installation
|
||||
PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@')
|
||||
|
||||
# Remove the line for this app
|
||||
ynh_app_setting_delete --key="go_version"
|
||||
|
||||
# Cleanup Go versions
|
||||
_ynh_go_cleanup
|
||||
}
|
||||
|
||||
# Remove no more needed versions of Go used by the app.
|
||||
#
|
||||
# [internal]
|
||||
#
|
||||
# This helper will check what Go version are no more required,
|
||||
# and uninstall them
|
||||
# If no app uses Go, goenv will be also removed.
|
||||
#
|
||||
# usage: _ynh_go_cleanup
|
||||
_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
|
||||
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
|
||||
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
|
||||
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
|
||||
# Remove goenv environment configuration
|
||||
ynh_print_info "Removing of goenv"
|
||||
ynh_safe_rm "$GOENV_INSTALL_DIR"
|
||||
ynh_safe_rm "/etc/profile.d/goenv.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
_ynh_go_try_bash_extension() {
|
||||
if [ -x src/configure ]; then
|
||||
src/configure && make -C src || {
|
||||
ynh_print_info "Optional bash extension failed to build, but things will still work normally."
|
||||
}
|
||||
fi
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue