mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Compare commits
No commits in common. "dev" and "debian/4.4.2.14" have entirely different histories.
dev
...
debian/4.4
389 changed files with 15859 additions and 35266 deletions
|
@ -1,2 +1,2 @@
|
||||||
[report]
|
[report]
|
||||||
omit=src/tests/*,src/vendor/*,/usr/lib/moulinette/yunohost/*,/usr/lib/python3/dist-packages/yunohost/tests/*,/usr/lib/python3/dist-packages/yunohost/vendor/*
|
omit=src/yunohost/tests/*,src/yunohost/vendor/*,/usr/lib/moulinette/yunohost/*
|
||||||
|
|
30
.github/workflows/autoblack.yml
vendored
30
.github/workflows/autoblack.yml
vendored
|
@ -1,30 +0,0 @@
|
||||||
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
|
|
42
.github/workflows/codeql.yml
vendored
42
.github/workflows/codeql.yml
vendored
|
@ -1,42 +0,0 @@
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "dev" ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ "dev" ]
|
|
||||||
paths-ignore:
|
|
||||||
- 'src/tests/**'
|
|
||||||
schedule:
|
|
||||||
- cron: '43 12 * * 3'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'python' ]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
queries: security-extended,security-and-quality
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
||||||
with:
|
|
||||||
category: "/language:${{matrix.language}}"
|
|
39
.github/workflows/n_updater.yml
vendored
39
.github/workflows/n_updater.yml
vendored
|
@ -1,39 +0,0 @@
|
||||||
# This workflow allows GitHub Actions to automagically update YunoHost NodeJS helper whenever a new release of n is detected.
|
|
||||||
name: Check for new n releases
|
|
||||||
on:
|
|
||||||
# Allow to manually trigger the workflow
|
|
||||||
workflow_dispatch:
|
|
||||||
# Run it every day at 5:00 UTC
|
|
||||||
schedule:
|
|
||||||
- cron: '0 5 * * *'
|
|
||||||
jobs:
|
|
||||||
updater:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Fetch the source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Run the updater script
|
|
||||||
id: run_updater
|
|
||||||
run: |
|
|
||||||
# Download n
|
|
||||||
wget https://raw.githubusercontent.com/tj/n/master/bin/n --output-document=helpers/vendor/n/n
|
|
||||||
|
|
||||||
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
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
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-${{ env.VERSION }}
|
|
||||||
delete-branch: true
|
|
||||||
title: 'Upgrade n to ${{ env.VERSION }}'
|
|
||||||
body: |
|
|
||||||
Upgrade `n` to ${{ env.VERSION }}
|
|
||||||
draft: false
|
|
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -31,14 +31,7 @@ pip-log.txt
|
||||||
.mr.developer.cfg
|
.mr.developer.cfg
|
||||||
|
|
||||||
# moulinette lib
|
# moulinette lib
|
||||||
src/locales
|
src/yunohost/locales
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
src/tests/apps
|
src/yunohost/tests/apps
|
||||||
|
|
||||||
# Tmp/local doc stuff
|
|
||||||
doc/bash-completion.sh
|
|
||||||
doc/bash_completion.d
|
|
||||||
doc/openapi.js
|
|
||||||
doc/openapi.json
|
|
||||||
doc/swagger
|
|
||||||
|
|
|
@ -16,9 +16,6 @@ default:
|
||||||
code_quality:
|
code_quality:
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_TAG # Only for tags
|
|
||||||
|
|
||||||
|
|
||||||
code_quality_html:
|
code_quality_html:
|
||||||
extends: code_quality
|
extends: code_quality
|
||||||
|
@ -26,9 +23,6 @@ code_quality_html:
|
||||||
REPORT_FORMAT: html
|
REPORT_FORMAT: html
|
||||||
artifacts:
|
artifacts:
|
||||||
paths: [gl-code-quality-report.html]
|
paths: [gl-code-quality-report.html]
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_TAG # Only for tags
|
|
||||||
|
|
||||||
|
|
||||||
# see: https://docs.gitlab.com/ee/ci/yaml/#switch-between-branch-pipelines-and-merge-request-pipelines
|
# see: https://docs.gitlab.com/ee/ci/yaml/#switch-between-branch-pipelines-and-merge-request-pipelines
|
||||||
workflow:
|
workflow:
|
||||||
|
@ -36,19 +30,14 @@ workflow:
|
||||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # If we move to gitlab one day
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # If we move to gitlab one day
|
||||||
- if: $CI_PIPELINE_SOURCE == "external_pull_request_event" # For github PR
|
- if: $CI_PIPELINE_SOURCE == "external_pull_request_event" # For github PR
|
||||||
- if: $CI_COMMIT_TAG # For tags
|
- if: $CI_COMMIT_TAG # For tags
|
||||||
- if: $CI_COMMIT_REF_NAME == "ci-format-$CI_DEFAULT_BRANCH" # Ignore black formatting branch created by the CI
|
- if: $CI_COMMIT_REF_NAME == "ci-format-dev" # Ignore black formatting branch created by the CI
|
||||||
when: never
|
|
||||||
- if: $CI_COMMIT_REF_NAME == "actions/black" # Ignore black formatting branch created by the CI
|
|
||||||
when: never
|
when: never
|
||||||
- if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" # If it's not the default branch and if it's a push, then do not trigger a build
|
- if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" # If it's not the default branch and if it's a push, then do not trigger a build
|
||||||
when: never
|
when: never
|
||||||
- when: always
|
- when: always
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
GIT_CLONE_PATH: '$CI_BUILDS_DIR/$CI_COMMIT_SHA/$CI_JOB_ID'
|
YNH_BUILD_DIR: "ynh-build"
|
||||||
YNH_SOURCE: "https://github.com/yunohost"
|
|
||||||
YNH_DEBIAN: "bullseye"
|
|
||||||
YNH_SKIP_DIAGNOSIS_DURING_UPGRADE: "true"
|
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- template: Code-Quality.gitlab-ci.yml
|
- template: Code-Quality.gitlab-ci.yml
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
.build-stage:
|
.build-stage:
|
||||||
stage: build
|
stage: build
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
variables:
|
variables:
|
||||||
YNH_BUILD_DIR: "$GIT_CLONE_PATH/build"
|
YNH_SOURCE: "https://github.com/yunohost"
|
||||||
before_script:
|
before_script:
|
||||||
- mkdir -p $YNH_BUILD_DIR
|
- mkdir -p $YNH_BUILD_DIR
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- ./*.deb
|
- $YNH_BUILD_DIR/*.deb
|
||||||
|
|
||||||
.build_script: &build_script
|
.build_script: &build_script
|
||||||
- cd $YNH_BUILD_DIR/$PACKAGE
|
- cd $YNH_BUILD_DIR/$PACKAGE
|
||||||
- VERSION=$(dpkg-parsechangelog -S Version 2>/dev/null)
|
- VERSION=$(dpkg-parsechangelog -S Version 2>/dev/null)
|
||||||
- VERSION_TIMESTAMPED="${VERSION}+$(date +%Y%m%d%H%M)"
|
- VERSION_NIGHTLY="${VERSION}+$(date +%Y%m%d%H%M)"
|
||||||
- dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_TIMESTAMPED}" -D "unstable" --force-distribution "CI build."
|
- dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_NIGHTLY}" -D "unstable" --force-distribution "Daily build."
|
||||||
- debuild --no-lintian -us -uc
|
- debuild --no-lintian -us -uc
|
||||||
- cp $YNH_BUILD_DIR/*.deb ${CI_PROJECT_DIR}/
|
|
||||||
- cd ${CI_PROJECT_DIR}
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# BUILD DEB
|
# BUILD DEB
|
||||||
|
@ -31,16 +29,18 @@ build-yunohost:
|
||||||
- mkdir -p $YNH_BUILD_DIR/$PACKAGE
|
- mkdir -p $YNH_BUILD_DIR/$PACKAGE
|
||||||
- cat archive.tar.gz | tar -xz -C $YNH_BUILD_DIR/$PACKAGE
|
- cat archive.tar.gz | tar -xz -C $YNH_BUILD_DIR/$PACKAGE
|
||||||
- rm archive.tar.gz
|
- rm archive.tar.gz
|
||||||
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
|
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
|
||||||
- *build_script
|
- *build_script
|
||||||
|
|
||||||
|
|
||||||
build-ssowat:
|
build-ssowat:
|
||||||
extends: .build-stage
|
extends: .build-stage
|
||||||
variables:
|
variables:
|
||||||
PACKAGE: "ssowat"
|
PACKAGE: "ssowat"
|
||||||
script:
|
script:
|
||||||
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $YNH_DEBIAN $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
|
- DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "ssowat \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+")
|
||||||
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
|
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
|
||||||
|
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
|
||||||
- *build_script
|
- *build_script
|
||||||
|
|
||||||
build-moulinette:
|
build-moulinette:
|
||||||
|
@ -48,6 +48,7 @@ build-moulinette:
|
||||||
variables:
|
variables:
|
||||||
PACKAGE: "moulinette"
|
PACKAGE: "moulinette"
|
||||||
script:
|
script:
|
||||||
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $YNH_DEBIAN $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
|
- DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "moulinette \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+")
|
||||||
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE
|
- git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1
|
||||||
|
- DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE
|
||||||
- *build_script
|
- *build_script
|
||||||
|
|
|
@ -4,28 +4,24 @@
|
||||||
|
|
||||||
generate-helpers-doc:
|
generate-helpers-doc:
|
||||||
stage: doc
|
stage: doc
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
before_script:
|
before_script:
|
||||||
|
- apt-get update -y && apt-get install git hub -y
|
||||||
- git config --global user.email "yunohost@yunohost.org"
|
- git config --global user.email "yunohost@yunohost.org"
|
||||||
- git config --global user.name "$GITHUB_USER"
|
- git config --global user.name "$GITHUB_USER"
|
||||||
script:
|
script:
|
||||||
- cd doc
|
- cd doc
|
||||||
- python3 generate_helper_doc.py 2
|
- python3 generate_helper_doc.py
|
||||||
- python3 generate_helper_doc.py 2.1
|
|
||||||
- python3 generate_resource_doc.py > resources.md
|
|
||||||
- hub clone https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/doc.git doc_repo
|
- 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.md doc_repo/pages/04.contribute/04.packaging_apps/11.helpers/packaging_apps_helpers.md
|
||||||
- cp helpers.v2.1.md doc_repo/pages/06.contribute/10.packaging_apps/20.scripts/12.helpers21/packaging_app_scripts_helpers_v21.md
|
|
||||||
- cp resources.md doc_repo/pages/06.contribute/10.packaging_apps/10.manifest/10.appresources/packaging_app_manifest_resources.md
|
|
||||||
- cd doc_repo
|
- cd doc_repo
|
||||||
# replace ${CI_COMMIT_REF_NAME} with ${CI_COMMIT_TAG} ?
|
# replace ${CI_COMMIT_REF_NAME} with ${CI_COMMIT_TAG} ?
|
||||||
- hub checkout -b "${CI_COMMIT_REF_NAME}"
|
- hub checkout -b "${CI_COMMIT_REF_NAME}"
|
||||||
- hub commit -am "[CI] Update app helpers/resources for ${CI_COMMIT_REF_NAME}"
|
- hub commit -am "[CI] Helper 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
|
- hub pull-request -m "[CI] Helper for ${CI_COMMIT_REF_NAME}" -p # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- doc/helpers.md
|
- doc/helpers.md
|
||||||
- doc/resources.md
|
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|
|
@ -14,14 +14,16 @@
|
||||||
|
|
||||||
upgrade:
|
upgrade:
|
||||||
extends: .install-stage
|
extends: .install-stage
|
||||||
image: "core-tests"
|
image: "after-install"
|
||||||
script:
|
script:
|
||||||
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
|
- 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 ./$YNH_BUILD_DIR/*.deb
|
||||||
|
|
||||||
|
|
||||||
install-postinstall:
|
install-postinstall:
|
||||||
extends: .install-stage
|
extends: .install-stage
|
||||||
image: "before-install"
|
image: "before-install"
|
||||||
script:
|
script:
|
||||||
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
|
- apt-get update -o Acquire::Retries=3
|
||||||
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace
|
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb
|
||||||
|
- yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace
|
||||||
|
|
|
@ -3,24 +3,47 @@
|
||||||
########################################
|
########################################
|
||||||
# later we must fix lint and format-check jobs and remove "allow_failure"
|
# later we must fix lint and format-check jobs and remove "allow_failure"
|
||||||
|
|
||||||
lint39:
|
---
|
||||||
|
lint37:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- tox -e py39-lint
|
- tox -e py37-lint
|
||||||
|
|
||||||
invalidcode39:
|
invalidcode37:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
- tox -e py39-invalidcode
|
- tox -e py37-invalidcode
|
||||||
|
|
||||||
mypy:
|
mypy:
|
||||||
stage: lint
|
stage: lint
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
- tox -e py39-mypy
|
- tox -e py37-mypy
|
||||||
|
|
||||||
|
black:
|
||||||
|
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 py37-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:
|
||||||
|
refs:
|
||||||
|
- dev
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
.install_debs: &install_debs
|
.install_debs: &install_debs
|
||||||
- DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb
|
- 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 ./$YNH_BUILD_DIR/*.deb
|
||||||
|
|
||||||
.test-stage:
|
.test-stage:
|
||||||
stage: test
|
stage: test
|
||||||
image: "core-tests"
|
image: "after-install"
|
||||||
variables:
|
variables:
|
||||||
PYTEST_ADDOPTS: "--color=yes"
|
PYTEST_ADDOPTS: "--color=yes"
|
||||||
before_script:
|
before_script:
|
||||||
- *install_debs
|
- *install_debs
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
- src/tests/apps
|
- src/yunohost/tests/apps
|
||||||
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
|
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
|
||||||
needs:
|
needs:
|
||||||
- job: build-yunohost
|
- job: build-yunohost
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: upgrade
|
- job: upgrade
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# TESTS
|
# TESTS
|
||||||
########################################
|
########################################
|
||||||
|
@ -32,10 +34,11 @@ full-tests:
|
||||||
PYTEST_ADDOPTS: "--color=yes"
|
PYTEST_ADDOPTS: "--color=yes"
|
||||||
before_script:
|
before_script:
|
||||||
- *install_debs
|
- *install_debs
|
||||||
- pip install mock pip pyOpenSSL pytest pytest-cov pytest-mock pytest-sugar requests-mock "packaging<22"
|
- yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace
|
||||||
- yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace
|
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest --cov=yunohost tests/ src/tests/ --junitxml=report.xml
|
- python3 -m pytest --cov=yunohost tests/ src/yunohost/tests/ data/hooks/diagnosis/ --junitxml=report.xml
|
||||||
|
- cd tests
|
||||||
|
- bash test_helpers.sh
|
||||||
needs:
|
needs:
|
||||||
- job: build-yunohost
|
- job: build-yunohost
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
@ -43,158 +46,163 @@ full-tests:
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: build-moulinette
|
- job: build-moulinette
|
||||||
artifacts: true
|
artifacts: true
|
||||||
coverage: '/TOTAL.*\s+(\d+%)/'
|
|
||||||
artifacts:
|
artifacts:
|
||||||
reports:
|
reports:
|
||||||
junit: report.xml
|
junit: report.xml
|
||||||
|
|
||||||
|
test-i18n-keys:
|
||||||
|
extends: .test-stage
|
||||||
|
script:
|
||||||
|
- python3 -m pytest tests/test_i18n_keys.py
|
||||||
|
only:
|
||||||
|
changes:
|
||||||
|
- locales/en.json
|
||||||
|
- src/yunohost/*.py
|
||||||
|
- data/hooks/diagnosis/*.py
|
||||||
|
|
||||||
|
test-translation-format-consistency:
|
||||||
|
extends: .test-stage
|
||||||
|
script:
|
||||||
|
- python3 -m pytest tests/test_translation_format_consistency.py
|
||||||
|
only:
|
||||||
|
changes:
|
||||||
|
- locales/*
|
||||||
|
|
||||||
test-actionmap:
|
test-actionmap:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest tests/test_actionmap.py
|
- python3 -m pytest tests/test_actionmap.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- share/actionsmap.yml
|
- data/actionsmap/*.yml
|
||||||
|
|
||||||
test-helpers2:
|
test-helpers:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- cd tests
|
- cd tests
|
||||||
- bash test_helpers.sh
|
- bash test_helpers.sh
|
||||||
|
only:
|
||||||
test-helpers2.1:
|
changes:
|
||||||
extends: .test-stage
|
- data/helpers.d/*
|
||||||
script:
|
|
||||||
- cd tests
|
|
||||||
- bash test_helpers.sh 2.1
|
|
||||||
|
|
||||||
test-domains:
|
test-domains:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_domains.py
|
- python3 -m pytest src/yunohost/tests/test_domains.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/domain.py
|
- src/yunohost/domain.py
|
||||||
|
|
||||||
test-dns:
|
test-dns:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_dns.py
|
- python3 -m pytest src/yunohost/tests/test_dns.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/dns.py
|
- src/yunohost/dns.py
|
||||||
- src/utils/dns.py
|
- src/yunohost/utils/dns.py
|
||||||
|
|
||||||
test-apps:
|
test-apps:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_apps.py
|
- python3 -m pytest src/yunohost/tests/test_apps.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/app.py
|
- src/yunohost/app.py
|
||||||
|
|
||||||
test-appscatalog:
|
test-appscatalog:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_app_catalog.py
|
- python3 -m pytest src/yunohost/tests/test_app_catalog.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/app_calalog.py
|
- src/yunohost/app_calalog.py
|
||||||
|
|
||||||
test-appurl:
|
test-appurl:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_appurl.py
|
- python3 -m pytest src/yunohost/tests/test_appurl.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/app.py
|
- src/yunohost/app.py
|
||||||
|
|
||||||
test-questions:
|
test-questions:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_questions.py
|
- python3 -m pytest src/yunohost/tests/test_questions.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/utils/config.py
|
- src/yunohost/utils/config.py
|
||||||
|
|
||||||
test-app-config:
|
test-app-config:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_app_config.py
|
- python3 -m pytest src/yunohost/tests/test_app_config.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/app.py
|
- src/yunohost/app.py
|
||||||
- src/utils/config.py
|
- src/yunohost/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
|
|
||||||
|
|
||||||
test-changeurl:
|
test-changeurl:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_changeurl.py
|
- python3 -m pytest src/yunohost/tests/test_changeurl.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/app.py
|
- src/yunohost/app.py
|
||||||
|
|
||||||
test-backuprestore:
|
test-backuprestore:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_backuprestore.py
|
- python3 -m pytest src/yunohost/tests/test_backuprestore.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/backup.py
|
- src/yunohost/backup.py
|
||||||
|
|
||||||
test-permission:
|
test-permission:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_permission.py
|
- python3 -m pytest src/yunohost/tests/test_permission.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/permission.py
|
- src/yunohost/permission.py
|
||||||
|
|
||||||
test-settings:
|
test-settings:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_settings.py
|
- python3 -m pytest src/yunohost/tests/test_settings.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/settings.py
|
- src/yunohost/settings.py
|
||||||
|
|
||||||
test-user-group:
|
test-user-group:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_user-group.py
|
- python3 -m pytest src/yunohost/tests/test_user-group.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/user.py
|
- src/yunohost/user.py
|
||||||
|
|
||||||
test-regenconf:
|
test-regenconf:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_regenconf.py
|
- python3 -m pytest src/yunohost/tests/test_regenconf.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/regenconf.py
|
- src/yunohost/regenconf.py
|
||||||
|
|
||||||
test-service:
|
test-service:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_service.py
|
- python3 -m pytest src/yunohost/tests/test_service.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/service.py
|
- src/yunohost/service.py
|
||||||
|
|
||||||
test-ldapauth:
|
test-ldapauth:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/tests/test_ldapauth.py
|
- python3 -m pytest src/yunohost/tests/test_ldapauth.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/authenticators/*.py
|
- src/yunohost/authenticators/*.py
|
||||||
|
|
|
@ -1,34 +1,27 @@
|
||||||
########################################
|
########################################
|
||||||
# TRANSLATION
|
# 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:
|
autofix-translated-strings:
|
||||||
stage: translation
|
stage: translation
|
||||||
image: "build-and-lint"
|
image: "before-install"
|
||||||
needs: []
|
needs: []
|
||||||
before_script:
|
before_script:
|
||||||
|
- apt-get update -y && apt-get install git hub -y
|
||||||
- git config --global user.email "yunohost@yunohost.org"
|
- git config --global user.email "yunohost@yunohost.org"
|
||||||
- git config --global user.name "$GITHUB_USER"
|
- git config --global user.name "$GITHUB_USER"
|
||||||
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
|
- git remote set-url origin https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git
|
||||||
- cd github_repo
|
|
||||||
script:
|
script:
|
||||||
|
- cd tests # Maybe move this script location to another folder?
|
||||||
# create a local branch that will overwrite distant one
|
# create a local branch that will overwrite distant one
|
||||||
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
|
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
|
||||||
- python3 maintenance/missing_i18n_keys.py --fix
|
- python3 remove_stale_translated_strings.py
|
||||||
- python3 maintenance/autofix_locale_format.py
|
- python3 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
|
- python3 reformat_locales.py
|
||||||
|
- '[ $(git diff -w | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
|
||||||
- git commit -am "[CI] Reformat / remove stale translated strings" || true
|
- 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}"
|
- git push -f origin "HEAD":"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
|
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
|
||||||
only:
|
only:
|
||||||
variables:
|
variables:
|
||||||
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
|
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
|
||||||
|
|
4
.lgtm.yml
Normal file
4
.lgtm.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
extraction:
|
||||||
|
python:
|
||||||
|
python_setup:
|
||||||
|
version: "3"
|
101
CONTRIBUTORS.md
Normal file
101
CONTRIBUTORS.md
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
YunoHost core contributors
|
||||||
|
==========================
|
||||||
|
|
||||||
|
YunoHost is built and maintained by the YunoHost project community.
|
||||||
|
Everyone is encouraged to submit issues and changes, and to contribute in other ways -- see https://yunohost.org/contribute to find out how.
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
Initial YunoHost core was built by Kload & beudbeud, for YunoHost v2.
|
||||||
|
|
||||||
|
Most of code was written by Kload and jerome, with help of numerous contributors.
|
||||||
|
|
||||||
|
Translation is made by a bunch of lovely people all over the world.
|
||||||
|
|
||||||
|
We would like to thank anyone who ever helped the YunoHost project <3
|
||||||
|
|
||||||
|
|
||||||
|
YunoHost core Contributors
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Jérôme Lebleu
|
||||||
|
- Kload
|
||||||
|
- Laurent 'Bram' Peuch
|
||||||
|
- Julien 'ju' Malik
|
||||||
|
- opi
|
||||||
|
- Aleks
|
||||||
|
- Adrien 'beudbeud' Beudin
|
||||||
|
- M5oul
|
||||||
|
- Valentin 'zamentur' / 'ljf' Grimaud
|
||||||
|
- Jocelyn Delalande
|
||||||
|
- infertux
|
||||||
|
- Taziden
|
||||||
|
- ZeHiro
|
||||||
|
- Josue-T
|
||||||
|
- nahoj
|
||||||
|
- a1ex
|
||||||
|
- JimboJoe
|
||||||
|
- vetetix
|
||||||
|
- jellium
|
||||||
|
- Sebastien 'sebian' Badia
|
||||||
|
- lmangani
|
||||||
|
- Julien Vaubourg
|
||||||
|
- thardev
|
||||||
|
- zimo2001
|
||||||
|
|
||||||
|
|
||||||
|
YunoHost core Translators
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
If you want to help translation, please visit https://translate.yunohost.org/projects/yunohost/yunohost/
|
||||||
|
|
||||||
|
|
||||||
|
### Dutch
|
||||||
|
|
||||||
|
- DUBWiSE
|
||||||
|
- Jeroen Keerl
|
||||||
|
- marut
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
- Bugsbane
|
||||||
|
- rokaz
|
||||||
|
|
||||||
|
### French
|
||||||
|
|
||||||
|
- aoz roon
|
||||||
|
- Genma
|
||||||
|
- Jean-Baptiste Holcroft
|
||||||
|
- Jean P.
|
||||||
|
- Jérôme Lebleu
|
||||||
|
- Lapineige
|
||||||
|
- paddy
|
||||||
|
|
||||||
|
|
||||||
|
### German
|
||||||
|
|
||||||
|
- david.bartke
|
||||||
|
- Fabian Gruber
|
||||||
|
- Felix Bartels
|
||||||
|
- Jeroen Keerl
|
||||||
|
- martin kistner
|
||||||
|
- Philip Gatzka
|
||||||
|
|
||||||
|
### Hindi
|
||||||
|
|
||||||
|
- Anmol
|
||||||
|
|
||||||
|
### Italian
|
||||||
|
|
||||||
|
- bricabrac
|
||||||
|
- Thomas Bille
|
||||||
|
|
||||||
|
### Portuguese
|
||||||
|
|
||||||
|
- Deleted User
|
||||||
|
- Trollken
|
||||||
|
|
||||||
|
### Spanish
|
||||||
|
|
||||||
|
- Juanu
|
||||||
|
|
43
README.md
43
README.md
|
@ -7,10 +7,10 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|

|
||||||
[](https://gitlab.com/yunohost/yunohost/-/pipelines)
|
[](https://gitlab.com/yunohost/yunohost/-/pipelines)
|
||||||

|

|
||||||
[](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
|
[](https://lgtm.com/projects/g/YunoHost/yunohost/context:python)
|
||||||
[](https://github.com/YunoHost/yunohost/security/code-scanning)
|
[](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
|
||||||
[](https://mastodon.social/@yunohost)
|
[](https://mastodon.social/@yunohost)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,49 +19,28 @@ 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.
|
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)
|
- [Project website](https://yunohost.org)
|
||||||
- [Install documentation](https://yunohost.org/install)
|
- [Install documentation](https://yunohost.org/install)
|
||||||
- [Issue tracker](https://github.com/YunoHost/issues)
|
- [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))
|
Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single sign-on user portal ([SSOwat](https://github.com/YunoHost/ssowat))
|
||||||
--- | ---
|
--- | ---
|
||||||
 | 
|
 | 
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
- You can learn how to get started with developing on YunoHost by reading [this piece of documentation](https://yunohost.org/dev).
|
- 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)!
|
- 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).
|
- You can help translate YunoHost on our [translation platform](https://translate.yunohost.org/engage/yunohost/?utm_source=widget)
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<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" />
|
<img src="https://translate.yunohost.org/widgets/yunohost/-/core/horizontal-auto.svg" alt="Translation status" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
As [other components of YunoHost](https://yunohost.org/faq), this repository is licensed under GNU AGPL v3.
|
As [other components of YunoHost](https://yunohost.org/#/faq_en), this repository is licensed under GNU AGPL v3.
|
||||||
|
|
||||||
## They support us <3
|
|
||||||
|
|
||||||
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 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 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>
|
|
||||||
|
|
||||||
This project was funded through the [NGI0 PET](https://nlnet.nl/PET) Fund, a fund established by NLnet with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 825310. If you're interested, [check out how to apply in this video](https://media.ccc.de/v/36c3-10795-ngi_zero_a_treasure_trove_of_it_innovation)!
|
|
||||||
|
|
61
bin/yunohost
61
bin/yunohost
|
@ -1,78 +1,67 @@
|
||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
sys.path.insert(0, "/usr/lib/moulinette/")
|
||||||
import yunohost
|
import yunohost
|
||||||
|
|
||||||
|
|
||||||
def _parse_cli_args():
|
def _parse_cli_args():
|
||||||
"""Parse additional arguments for the cli"""
|
"""Parse additional arguments for the cli"""
|
||||||
parser = argparse.ArgumentParser(add_help=False)
|
parser = argparse.ArgumentParser(add_help=False)
|
||||||
parser.add_argument(
|
parser.add_argument('--output-as',
|
||||||
"--output-as",
|
choices=['json', 'plain', 'none'], default=None,
|
||||||
choices=["json", "plain", "none"],
|
help="Output result in another format"
|
||||||
default=None,
|
|
||||||
help="Output result in another format",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument('--debug',
|
||||||
"--debug",
|
action='store_true', default=False,
|
||||||
action="store_true",
|
help="Log and print debug messages"
|
||||||
default=False,
|
|
||||||
help="Log and print debug messages",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument('--quiet',
|
||||||
"--quiet", action="store_true", default=False, help="Don't produce any output"
|
action='store_true', default=False,
|
||||||
|
help="Don't produce any output"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument('--timeout',
|
||||||
"--version", action="store_true", default=False, help="Display YunoHost packages versions (alias to 'yunohost tools versions')"
|
type=int, default=None,
|
||||||
)
|
help="Number of seconds before this command will timeout because it can't acquire the lock (meaning that another command is currently running), by default there is no timeout and the command will wait until it can get the lock"
|
||||||
parser.add_argument(
|
|
||||||
"--timeout",
|
|
||||||
type=int,
|
|
||||||
default=None,
|
|
||||||
help="Number of seconds before this command will timeout because it can't acquire the lock (meaning that another command is currently running), by default there is no timeout and the command will wait until it can get the lock",
|
|
||||||
)
|
)
|
||||||
# deprecated arguments
|
# deprecated arguments
|
||||||
parser.add_argument(
|
parser.add_argument('--plain',
|
||||||
"--plain", action="store_true", default=False, help=argparse.SUPPRESS
|
action='store_true', default=False, help=argparse.SUPPRESS
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument('--json',
|
||||||
"--json", action="store_true", default=False, help=argparse.SUPPRESS
|
action='store_true', default=False, help=argparse.SUPPRESS
|
||||||
)
|
)
|
||||||
|
|
||||||
opts, args = parser.parse_known_args()
|
opts, args = parser.parse_known_args()
|
||||||
|
|
||||||
# output compatibility
|
# output compatibility
|
||||||
if opts.plain:
|
if opts.plain:
|
||||||
opts.output_as = "plain"
|
opts.output_as = 'plain'
|
||||||
elif opts.json:
|
elif opts.json:
|
||||||
opts.output_as = "json"
|
opts.output_as = 'json'
|
||||||
|
|
||||||
return (parser, opts, args)
|
return (parser, opts, args)
|
||||||
|
|
||||||
|
|
||||||
# Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ...
|
# Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ...
|
||||||
|
|
||||||
default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
if os.environ["PATH"] != default_path:
|
if os.environ["PATH"] != default_path:
|
||||||
os.environ["PATH"] = default_path + ":" + os.environ["PATH"]
|
os.environ["PATH"] = default_path + ":" + os.environ["PATH"]
|
||||||
|
|
||||||
# Main action ----------------------------------------------------------
|
# Main action ----------------------------------------------------------
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
if os.geteuid() != 0:
|
if os.geteuid() != 0:
|
||||||
sys.stderr.write(
|
sys.stderr.write("\033[1;31mError:\033[0m yunohost command must be "
|
||||||
"\033[1;31mError:\033[0m yunohost command must be "
|
"run as root or with sudo.\n")
|
||||||
"run as root or with sudo.\n"
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
parser, opts, args = _parse_cli_args()
|
parser, opts, args = _parse_cli_args()
|
||||||
|
|
||||||
if opts.version:
|
|
||||||
args = ["tools", "versions"]
|
|
||||||
|
|
||||||
# Execute the action
|
# Execute the action
|
||||||
yunohost.cli(
|
yunohost.cli(
|
||||||
debug=opts.debug,
|
debug=opts.debug,
|
||||||
|
@ -80,5 +69,5 @@ if __name__ == "__main__":
|
||||||
output_as=opts.output_as,
|
output_as=opts.output_as,
|
||||||
timeout=opts.timeout,
|
timeout=opts.timeout,
|
||||||
args=args,
|
args=args,
|
||||||
parser=parser,
|
parser=parser
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,52 +1,44 @@
|
||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
sys.path.insert(0, "/usr/lib/moulinette/")
|
||||||
import yunohost
|
import yunohost
|
||||||
|
|
||||||
# Default server configuration
|
# Default server configuration
|
||||||
DEFAULT_HOST = "localhost"
|
DEFAULT_HOST = 'localhost'
|
||||||
DEFAULT_PORT = 6787
|
DEFAULT_PORT = 6787
|
||||||
|
|
||||||
|
|
||||||
def _parse_api_args():
|
def _parse_api_args():
|
||||||
"""Parse main arguments for the api"""
|
"""Parse main arguments for the api"""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(add_help=False,
|
||||||
add_help=False,
|
|
||||||
description="Run the YunoHost API to manage your server.",
|
description="Run the YunoHost API to manage your server.",
|
||||||
)
|
)
|
||||||
srv_group = parser.add_argument_group("server configuration")
|
srv_group = parser.add_argument_group('server configuration')
|
||||||
srv_group.add_argument(
|
srv_group.add_argument('-h', '--host',
|
||||||
"-h",
|
action='store', default=DEFAULT_HOST,
|
||||||
"--host",
|
|
||||||
action="store",
|
|
||||||
default=DEFAULT_HOST,
|
|
||||||
help="Host to listen on (default: %s)" % DEFAULT_HOST,
|
help="Host to listen on (default: %s)" % DEFAULT_HOST,
|
||||||
)
|
)
|
||||||
srv_group.add_argument(
|
srv_group.add_argument('-p', '--port',
|
||||||
"-p",
|
action='store', default=DEFAULT_PORT, type=int,
|
||||||
"--port",
|
|
||||||
action="store",
|
|
||||||
default=DEFAULT_PORT,
|
|
||||||
type=int,
|
|
||||||
help="Port to listen on (default: %d)" % DEFAULT_PORT,
|
help="Port to listen on (default: %d)" % DEFAULT_PORT,
|
||||||
)
|
)
|
||||||
glob_group = parser.add_argument_group("global arguments")
|
glob_group = parser.add_argument_group('global arguments')
|
||||||
glob_group.add_argument(
|
glob_group.add_argument('--debug',
|
||||||
"--debug",
|
action='store_true', default=False,
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
help="Set log level to DEBUG",
|
help="Set log level to DEBUG",
|
||||||
)
|
)
|
||||||
glob_group.add_argument(
|
glob_group.add_argument('--help',
|
||||||
"--help",
|
action='help', help="Show this help message and exit",
|
||||||
action="help",
|
|
||||||
help="Show this help message and exit",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
opts = _parse_api_args()
|
opts = _parse_api_args()
|
||||||
# Run the server
|
# Run the server
|
||||||
yunohost.api(debug=opts.debug, host=opts.host, port=opts.port)
|
yunohost.api(debug=opts.debug, host=opts.host, port=opts.port)
|
||||||
|
|
41
bin/yunomdns
41
bin/yunomdns
|
@ -21,20 +21,8 @@ def get_network_local_interfaces() -> Dict[str, Dict[str, List[str]]]:
|
||||||
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
adapter.name: {
|
adapter.name: {
|
||||||
"ipv4": [
|
"ipv4": [ip.ip for ip in adapter.ips if ip.is_IPv4 and ip_address(ip.ip).is_private and not ip_address(ip.ip).is_link_local],
|
||||||
ip.ip
|
"ipv6": [ip.ip[0] for ip in adapter.ips if ip.is_IPv6 and ip_address(ip.ip[0]).is_private and not ip_address(ip.ip[0]).is_link_local],
|
||||||
for ip in adapter.ips
|
|
||||||
if ip.is_IPv4
|
|
||||||
and ip_address(ip.ip).is_private
|
|
||||||
and not ip_address(ip.ip).is_link_local
|
|
||||||
],
|
|
||||||
"ipv6": [
|
|
||||||
ip.ip[0]
|
|
||||||
for ip in adapter.ips
|
|
||||||
if ip.is_IPv6
|
|
||||||
and ip_address(ip.ip[0]).is_private
|
|
||||||
and not ip_address(ip.ip[0]).is_link_local
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
for adapter in ifaddr.get_adapters()
|
for adapter in ifaddr.get_adapters()
|
||||||
if adapter.name != "lo"
|
if adapter.name != "lo"
|
||||||
|
@ -45,6 +33,7 @@ def get_network_local_interfaces() -> Dict[str, Dict[str, List[str]]]:
|
||||||
# Listener class, to detect duplicates on the network
|
# Listener class, to detect duplicates on the network
|
||||||
# Stores the list of servers in its list property
|
# Stores the list of servers in its list property
|
||||||
class Listener:
|
class Listener:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.list = []
|
self.list = []
|
||||||
|
|
||||||
|
@ -77,18 +66,14 @@ def main() -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if "interfaces" not in config:
|
if "interfaces" not in config:
|
||||||
config["interfaces"] = [
|
config["interfaces"] = [interface
|
||||||
interface
|
|
||||||
for interface, local_ips in interfaces.items()
|
for interface, local_ips in interfaces.items()
|
||||||
if local_ips["ipv4"]
|
if local_ips["ipv4"]]
|
||||||
]
|
|
||||||
|
|
||||||
if "ban_interfaces" in config:
|
if "ban_interfaces" in config:
|
||||||
config["interfaces"] = [
|
config["interfaces"] = [interface
|
||||||
interface
|
|
||||||
for interface in config["interfaces"]
|
for interface in config["interfaces"]
|
||||||
if interface not in config["ban_interfaces"]
|
if interface not in config["ban_interfaces"]]
|
||||||
]
|
|
||||||
|
|
||||||
# Let's discover currently published .local domains accross the network
|
# Let's discover currently published .local domains accross the network
|
||||||
zc = Zeroconf()
|
zc = Zeroconf()
|
||||||
|
@ -118,18 +103,14 @@ def main() -> bool:
|
||||||
|
|
||||||
return domain_i
|
return domain_i
|
||||||
|
|
||||||
config["domains"] = [
|
config['domains'] = [find_domain_not_already_published(domain) for domain in config['domains']]
|
||||||
find_domain_not_already_published(domain) for domain in config["domains"]
|
|
||||||
]
|
|
||||||
|
|
||||||
zcs: Dict[Zeroconf, List[ServiceInfo]] = {}
|
zcs: Dict[Zeroconf, List[ServiceInfo]] = {}
|
||||||
|
|
||||||
for interface in config["interfaces"]:
|
for interface in config["interfaces"]:
|
||||||
|
|
||||||
if interface not in interfaces:
|
if interface not in interfaces:
|
||||||
print(
|
print(f"Interface {interface} listed in config file is not present on system.")
|
||||||
f"Interface {interface} listed in config file is not present on system."
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
|
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
|
||||||
|
@ -168,9 +149,7 @@ def main() -> bool:
|
||||||
print("Registering...")
|
print("Registering...")
|
||||||
for zc, infos in zcs.items():
|
for zc, infos in zcs.items():
|
||||||
for info in infos:
|
for info in infos:
|
||||||
zc.register_service(
|
zc.register_service(info, allow_name_change=True, cooperating_responders=True)
|
||||||
info, allow_name_change=True, cooperating_responders=True
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print("Registered. Press Ctrl+C or stop service to stop.")
|
print("Registered. Press Ctrl+C or stop service to stop.")
|
||||||
|
|
|
@ -1,34 +1,77 @@
|
||||||
#!/usr/bin/env python3
|
#!/bin/bash
|
||||||
|
|
||||||
import sys
|
set -e
|
||||||
import requests
|
set -u
|
||||||
import json
|
|
||||||
|
|
||||||
SERVER_URL = "https://paste.yunohost.org"
|
PASTE_URL="https://paste.yunohost.org"
|
||||||
TIMEOUT = 3
|
|
||||||
|
|
||||||
def create_snippet(data):
|
_die() {
|
||||||
try:
|
printf "Error: %s\n" "$*"
|
||||||
url = SERVER_URL + "/documents"
|
exit 1
|
||||||
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."
|
||||||
|
}
|
||||||
|
|
||||||
def main():
|
paste_data() {
|
||||||
output = sys.stdin.read()
|
json=$(curl -X POST -s -d "$1" "${PASTE_URL}/documents")
|
||||||
|
[[ -z "$json" ]] && _die "Unable to post the data to the server."
|
||||||
|
|
||||||
if not output:
|
key=$(echo "$json" \
|
||||||
print("\033[31mError: No input received from stdin.\033[0m")
|
| python -c 'import json,sys;o=json.load(sys.stdin);print o["key"]' \
|
||||||
sys.exit(1)
|
2>/dev/null)
|
||||||
|
[[ -z "$key" ]] && _die "Unable to parse the server response."
|
||||||
|
|
||||||
url = create_snippet(output)
|
echo "${PASTE_URL}/${key}"
|
||||||
|
}
|
||||||
|
|
||||||
print("\033[32mURL: {}\033[0m".format(url))
|
usage() {
|
||||||
|
printf "Usage: ${0} [OPTION]...
|
||||||
|
|
||||||
if __name__ == "__main__":
|
Read from input stream and paste the data to the YunoHost
|
||||||
main()
|
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 "${@}"
|
||||||
|
|
|
@ -56,7 +56,7 @@ EOF
|
||||||
|
|
||||||
echo "$LOGO_AND_FINGERPRINTS" > /etc/issue
|
echo "$LOGO_AND_FINGERPRINTS" > /etc/issue
|
||||||
|
|
||||||
if ! groups | grep -q all_users && [[ ! -f /etc/yunohost/installed ]]
|
if [[ ! -f /etc/yunohost/installed ]]
|
||||||
then
|
then
|
||||||
chvt 2
|
chvt 2
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ then
|
||||||
You should now proceed with YunoHost post-installation. This is where you will
|
You should now proceed with YunoHost post-installation. This is where you will
|
||||||
be asked for:
|
be asked for:
|
||||||
- the main domain of your server;
|
- the main domain of your server;
|
||||||
- the username and password for the first admin
|
- the administration password.
|
||||||
|
|
||||||
You can perform this step:
|
You can perform this step:
|
||||||
- from your web browser, by accessing: https://yunohost.local/ or ${local_ip}
|
- from your web browser, by accessing: https://yunohost.local/ or ${local_ip}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# Fail2Ban filter for postfix authentication failures
|
|
||||||
[INCLUDES]
|
|
||||||
before = common.conf
|
|
||||||
[Definition]
|
|
||||||
_daemon = postfix/smtpd
|
|
||||||
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$
|
|
|
@ -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,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,86 +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,7 +0,0 @@
|
||||||
error_page 502 /502.html;
|
|
||||||
|
|
||||||
location = /502.html {
|
|
||||||
|
|
||||||
root /usr/share/yunohost/html/;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
location / {
|
|
||||||
return 302 https://$host/yunohost/admin;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
server_host = localhost
|
|
||||||
server_port = 389
|
|
||||||
search_base = dc=yunohost,dc=org
|
|
||||||
query_filter = (&(objectClass=groupOfNamesYnh)(mail=%s))
|
|
||||||
scope = sub
|
|
||||||
result_attribute = memberUid, mail
|
|
||||||
terminal_result_attribute = memberUid
|
|
|
@ -1,4 +0,0 @@
|
||||||
# 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,2 +0,0 @@
|
||||||
# set redis server
|
|
||||||
servers = "127.0.0.1";
|
|
444
share/actionsmap.yml → data/actionsmap/yunohost.yml
Executable file → Normal file
444
share/actionsmap.yml → data/actionsmap/yunohost.yml
Executable file → Normal file
|
@ -33,10 +33,18 @@
|
||||||
# Global parameters #
|
# Global parameters #
|
||||||
#############################
|
#############################
|
||||||
_global:
|
_global:
|
||||||
namespace: yunohost
|
name: yunohost.admin
|
||||||
authentication:
|
authentication:
|
||||||
api: ldap_admin
|
api: ldap_admin
|
||||||
cli: null
|
cli: null
|
||||||
|
arguments:
|
||||||
|
-v:
|
||||||
|
full: --version
|
||||||
|
help: Display YunoHost packages versions
|
||||||
|
action: callback
|
||||||
|
callback:
|
||||||
|
method: yunohost.utils.packages.ynh_packages_version
|
||||||
|
return: true
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# User #
|
# User #
|
||||||
|
@ -63,33 +71,27 @@ user:
|
||||||
help: The unique username to create
|
help: The unique username to create
|
||||||
extra:
|
extra:
|
||||||
pattern: &pattern_username
|
pattern: &pattern_username
|
||||||
- !!str ^[a-z0-9_\.]+$
|
- !!str ^[a-z0-9_]+$
|
||||||
- "pattern_username"
|
- "pattern_username"
|
||||||
-F:
|
|
||||||
full: --fullname
|
|
||||||
help: The full name of the user. For example 'Camille Dupont'
|
|
||||||
extra:
|
|
||||||
ask: ask_fullname
|
|
||||||
required: False
|
|
||||||
pattern: &pattern_fullname
|
|
||||||
- !!str ^([^\W_]{1,30}[ ,.'-]{0,3})+$
|
|
||||||
- "pattern_fullname"
|
|
||||||
-f:
|
-f:
|
||||||
full: --firstname
|
full: --firstname
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
extra:
|
||||||
required: False
|
ask: ask_firstname
|
||||||
|
required: True
|
||||||
pattern: &pattern_firstname
|
pattern: &pattern_firstname
|
||||||
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
||||||
- "pattern_firstname"
|
- "pattern_firstname"
|
||||||
-l:
|
-l:
|
||||||
full: --lastname
|
full: --lastname
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
extra:
|
||||||
required: False
|
ask: ask_lastname
|
||||||
|
required: True
|
||||||
pattern: &pattern_lastname
|
pattern: &pattern_lastname
|
||||||
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
- !!str ^([^\W\d_]{1,30}[ ,.'-]{0,3})+$
|
||||||
- "pattern_lastname"
|
- "pattern_lastname"
|
||||||
|
-m:
|
||||||
|
full: --mail
|
||||||
|
help: (Deprecated, see --domain) Main unique email address
|
||||||
-p:
|
-p:
|
||||||
full: --password
|
full: --password
|
||||||
help: User password
|
help: User password
|
||||||
|
@ -116,11 +118,6 @@ user:
|
||||||
pattern: &pattern_mailbox_quota
|
pattern: &pattern_mailbox_quota
|
||||||
- !!str ^(\d+[bkMGT])|0$
|
- !!str ^(\d+[bkMGT])|0$
|
||||||
- "pattern_mailbox_quota"
|
- "pattern_mailbox_quota"
|
||||||
-s:
|
|
||||||
full: --loginShell
|
|
||||||
help: The login shell used
|
|
||||||
default: "/bin/bash"
|
|
||||||
|
|
||||||
|
|
||||||
### user_delete()
|
### user_delete()
|
||||||
delete:
|
delete:
|
||||||
|
@ -142,19 +139,12 @@ user:
|
||||||
arguments:
|
arguments:
|
||||||
username:
|
username:
|
||||||
help: Username to update
|
help: Username to update
|
||||||
-F:
|
|
||||||
full: --fullname
|
|
||||||
help: The full name of the user. For example 'Camille Dupont'
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_fullname
|
|
||||||
-f:
|
-f:
|
||||||
full: --firstname
|
full: --firstname
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_firstname
|
pattern: *pattern_firstname
|
||||||
-l:
|
-l:
|
||||||
full: --lastname
|
full: --lastname
|
||||||
help: Deprecated. Use --fullname instead.
|
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_lastname
|
pattern: *pattern_lastname
|
||||||
-m:
|
-m:
|
||||||
|
@ -200,10 +190,6 @@ user:
|
||||||
metavar: "{SIZE|0}"
|
metavar: "{SIZE|0}"
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_mailbox_quota
|
pattern: *pattern_mailbox_quota
|
||||||
-s:
|
|
||||||
full: --loginShell
|
|
||||||
help: The login shell used
|
|
||||||
default: "/bin/bash"
|
|
||||||
|
|
||||||
### user_info()
|
### user_info()
|
||||||
info:
|
info:
|
||||||
|
@ -322,35 +308,6 @@ user:
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_username
|
pattern: *pattern_username
|
||||||
|
|
||||||
add-mailalias:
|
|
||||||
action_help: Add mail aliases to group
|
|
||||||
api: PUT /users/groups/<groupname>/aliases/<aliases>
|
|
||||||
arguments:
|
|
||||||
groupname:
|
|
||||||
help: Name of the group to add user(s) to
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_groupname
|
|
||||||
aliases:
|
|
||||||
help: Mail aliases to add
|
|
||||||
nargs: "+"
|
|
||||||
metavar: MAIL
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_email
|
|
||||||
remove-mailalias:
|
|
||||||
action_help: Remove mail aliases to group
|
|
||||||
api: DELETE /users/groups/<groupname>/aliases/<aliases>
|
|
||||||
arguments:
|
|
||||||
groupname:
|
|
||||||
help: Name of the group to add user(s) to
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_groupname
|
|
||||||
aliases:
|
|
||||||
help: Mail aliases to remove
|
|
||||||
nargs: "+"
|
|
||||||
metavar: MAIL
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
permission:
|
permission:
|
||||||
subcategory_help: Manage permissions
|
subcategory_help: Manage permissions
|
||||||
actions:
|
actions:
|
||||||
|
@ -489,22 +446,6 @@ domain:
|
||||||
--exclude-subdomains:
|
--exclude-subdomains:
|
||||||
help: Filter out domains that are obviously subdomains of other declared domains
|
help: Filter out domains that are obviously subdomains of other declared domains
|
||||||
action: store_true
|
action: store_true
|
||||||
--tree:
|
|
||||||
help: Display domains as a tree
|
|
||||||
action: store_true
|
|
||||||
--features:
|
|
||||||
help: List only domains with features enabled (xmpp, mail_in, mail_out)
|
|
||||||
nargs: "*"
|
|
||||||
|
|
||||||
### domain_info()
|
|
||||||
info:
|
|
||||||
action_help: Get domain aggredated data
|
|
||||||
api: GET /domains/<domain>
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Domain to check
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_domain
|
|
||||||
|
|
||||||
### domain_add()
|
### domain_add()
|
||||||
add:
|
add:
|
||||||
|
@ -515,16 +456,10 @@ domain:
|
||||||
help: Domain name to add
|
help: Domain name to add
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_domain
|
pattern: *pattern_domain
|
||||||
--ignore-dyndns:
|
-d:
|
||||||
help: If adding a DynDNS domain, only add the domain, without subscribing to the DynDNS service
|
full: --dyndns
|
||||||
|
help: Subscribe to the DynDNS service
|
||||||
action: store_true
|
action: store_true
|
||||||
--dyndns-recovery-password:
|
|
||||||
metavar: PASSWORD
|
|
||||||
nargs: "?"
|
|
||||||
const: 0
|
|
||||||
help: If adding a DynDNS domain, subscribe to the DynDNS service with a password, used to later delete the domain
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
### domain_remove()
|
### domain_remove()
|
||||||
remove:
|
remove:
|
||||||
|
@ -543,16 +478,6 @@ domain:
|
||||||
full: --force
|
full: --force
|
||||||
help: Do not ask confirmation to remove apps
|
help: Do not ask confirmation to remove apps
|
||||||
action: store_true
|
action: store_true
|
||||||
--ignore-dyndns:
|
|
||||||
help: If removing a DynDNS domain, only remove the domain, without unsubscribing from the DynDNS service
|
|
||||||
action: store_true
|
|
||||||
--dyndns-recovery-password:
|
|
||||||
metavar: PASSWORD
|
|
||||||
nargs: "?"
|
|
||||||
const: 0
|
|
||||||
help: If removing a DynDNS domain, unsubscribe from the DynDNS service with a password
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
|
|
||||||
### domain_dns_conf()
|
### domain_dns_conf()
|
||||||
|
@ -570,7 +495,9 @@ domain:
|
||||||
action_help: Check the current main domain, or change it
|
action_help: Check the current main domain, or change it
|
||||||
deprecated_alias:
|
deprecated_alias:
|
||||||
- maindomain
|
- maindomain
|
||||||
api: PUT /domains/<new_main_domain>/main
|
api:
|
||||||
|
- GET /domains/main
|
||||||
|
- PUT /domains/<new_main_domain>/main
|
||||||
arguments:
|
arguments:
|
||||||
-n:
|
-n:
|
||||||
full: --new-main-domain
|
full: --new-main-domain
|
||||||
|
@ -607,6 +534,9 @@ domain:
|
||||||
--self-signed:
|
--self-signed:
|
||||||
help: Install self-signed certificate instead of Let's Encrypt
|
help: Install self-signed certificate instead of Let's Encrypt
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--staging:
|
||||||
|
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### certificate_renew()
|
### certificate_renew()
|
||||||
cert-renew:
|
cert-renew:
|
||||||
|
@ -617,7 +547,7 @@ domain:
|
||||||
help: Domains for which to renew the certificates
|
help: Domains for which to renew the certificates
|
||||||
nargs: "*"
|
nargs: "*"
|
||||||
--force:
|
--force:
|
||||||
help: Ignore the validity threshold (15 days)
|
help: Ignore the validity threshold (30 days)
|
||||||
action: store_true
|
action: store_true
|
||||||
--email:
|
--email:
|
||||||
help: Send an email to root with logs if some renewing fails
|
help: Send an email to root with logs if some renewing fails
|
||||||
|
@ -625,10 +555,12 @@ domain:
|
||||||
--no-checks:
|
--no-checks:
|
||||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--staging:
|
||||||
|
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### domain_url_available()
|
### domain_url_available()
|
||||||
url-available:
|
url-available:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Check availability of a web path
|
action_help: Check availability of a web path
|
||||||
api: GET /domain/<domain>/urlavailable
|
api: GET /domain/<domain>/urlavailable
|
||||||
arguments:
|
arguments:
|
||||||
|
@ -639,83 +571,16 @@ domain:
|
||||||
path:
|
path:
|
||||||
help: The path to check (e.g. /coffee)
|
help: The path to check (e.g. /coffee)
|
||||||
|
|
||||||
|
|
||||||
### domain_action_run()
|
|
||||||
action-run:
|
|
||||||
hide_in_help: True
|
|
||||||
action_help: Run domain action
|
|
||||||
api: PUT /domain/<domain>/actions/<action>
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Domain name
|
|
||||||
action:
|
|
||||||
help: action id
|
|
||||||
-a:
|
|
||||||
full: --args
|
|
||||||
help: Serialized arguments for action (i.e. "foo=bar&lorem=ipsum")
|
|
||||||
|
|
||||||
subcategories:
|
subcategories:
|
||||||
dyndns:
|
|
||||||
subcategory_help: Subscribe and Update DynDNS Hosts
|
|
||||||
actions:
|
|
||||||
### domain_dyndns_subscribe()
|
|
||||||
subscribe:
|
|
||||||
action_help: Subscribe to a DynDNS service
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Domain to subscribe to the DynDNS service
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_domain
|
|
||||||
-p:
|
|
||||||
full: --recovery-password
|
|
||||||
nargs: "?"
|
|
||||||
const: 0
|
|
||||||
help: Password used to later recover the domain if needed
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
### domain_dyndns_unsubscribe()
|
|
||||||
unsubscribe:
|
|
||||||
action_help: Unsubscribe from a DynDNS service
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Domain to unsubscribe from the DynDNS service
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_domain
|
|
||||||
required: True
|
|
||||||
-p:
|
|
||||||
full: --recovery-password
|
|
||||||
nargs: "?"
|
|
||||||
const: 0
|
|
||||||
help: Recovery password used to delete the domain
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
### domain_dyndns_set_recovery_password()
|
|
||||||
set-recovery-password:
|
|
||||||
action_help: Set recovery password
|
|
||||||
arguments:
|
|
||||||
domain:
|
|
||||||
help: Domain to set recovery password for
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_domain
|
|
||||||
required: True
|
|
||||||
-p:
|
|
||||||
full: --recovery-password
|
|
||||||
help: The new recovery password
|
|
||||||
extra:
|
|
||||||
password: ask_dyndns_recovery_password
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
config:
|
config:
|
||||||
subcategory_help: Domain settings
|
subcategory_help: Domain settings
|
||||||
actions:
|
actions:
|
||||||
|
|
||||||
### domain_config_get()
|
### domain_config_get()
|
||||||
get:
|
get:
|
||||||
action_help: Display a domain configuration
|
action_help: Display a domain configuration
|
||||||
api:
|
api: GET /domains/<domain>/config
|
||||||
- GET /domains/<domain>/config
|
|
||||||
- GET /domains/<domain>/config/<key>
|
|
||||||
arguments:
|
arguments:
|
||||||
domain:
|
domain:
|
||||||
help: Domain name
|
help: Domain name
|
||||||
|
@ -734,7 +599,7 @@ domain:
|
||||||
### domain_config_set()
|
### domain_config_set()
|
||||||
set:
|
set:
|
||||||
action_help: Apply a new configuration
|
action_help: Apply a new configuration
|
||||||
api: PUT /domains/<domain>/config/<key>
|
api: PUT /domains/<domain>/config
|
||||||
arguments:
|
arguments:
|
||||||
domain:
|
domain:
|
||||||
help: Domain name
|
help: Domain name
|
||||||
|
@ -815,6 +680,9 @@ domain:
|
||||||
--self-signed:
|
--self-signed:
|
||||||
help: Install self-signed certificate instead of Let's Encrypt
|
help: Install self-signed certificate instead of Let's Encrypt
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--staging:
|
||||||
|
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### certificate_renew()
|
### certificate_renew()
|
||||||
renew:
|
renew:
|
||||||
|
@ -833,6 +701,9 @@ domain:
|
||||||
--no-checks:
|
--no-checks:
|
||||||
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--staging:
|
||||||
|
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
|
||||||
|
action: store_true
|
||||||
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
|
@ -854,10 +725,6 @@ app:
|
||||||
full: --with-categories
|
full: --with-categories
|
||||||
help: Also return a list of app categories
|
help: Also return a list of app categories
|
||||||
action: store_true
|
action: store_true
|
||||||
-a:
|
|
||||||
full: --with-antifeatures
|
|
||||||
help: Also return a list of antifeatures categories
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### app_search()
|
### app_search()
|
||||||
search:
|
search:
|
||||||
|
@ -873,10 +740,9 @@ app:
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
help: Name, local path or git URL of the app to fetch the manifest of
|
help: Name, local path or git URL of the app to fetch the manifest of
|
||||||
-s:
|
|
||||||
full: --with-screenshot
|
fetchlist:
|
||||||
help: Also return a base64 screenshot if any (API only)
|
deprecated: true
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### app_list()
|
### app_list()
|
||||||
list:
|
list:
|
||||||
|
@ -887,10 +753,12 @@ app:
|
||||||
full: --full
|
full: --full
|
||||||
help: Display all details, including the app manifest and various other infos
|
help: Display all details, including the app manifest and various other infos
|
||||||
action: store_true
|
action: store_true
|
||||||
-u:
|
-i:
|
||||||
full: --upgradable
|
full: --installed
|
||||||
help: List only apps that can upgrade to a newer version
|
help: Dummy argument, does nothing anymore (still there only for backward compatibility)
|
||||||
action: store_true
|
action: store_true
|
||||||
|
filter:
|
||||||
|
nargs: '?'
|
||||||
|
|
||||||
### app_info()
|
### app_info()
|
||||||
info:
|
info:
|
||||||
|
@ -934,14 +802,14 @@ app:
|
||||||
help: Custom name for the app
|
help: Custom name for the app
|
||||||
-a:
|
-a:
|
||||||
full: --args
|
full: --args
|
||||||
help: Serialized arguments for app script (i.e. "domain=domain.tld&path=/path&init_main_permission=visitors")
|
help: Serialized arguments for app script (i.e. "domain=domain.tld&path=/path")
|
||||||
-n:
|
-n:
|
||||||
full: --no-remove-on-failure
|
full: --no-remove-on-failure
|
||||||
help: Debug option to avoid removing the app on a failed installation
|
help: Debug option to avoid removing the app on a failed installation
|
||||||
action: store_true
|
action: store_true
|
||||||
-f:
|
-f:
|
||||||
full: --force
|
full: --force
|
||||||
help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party), or when the app displays a post-install notification
|
help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party)
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
### app_remove()
|
### app_remove()
|
||||||
|
@ -978,10 +846,6 @@ app:
|
||||||
full: --no-safety-backup
|
full: --no-safety-backup
|
||||||
help: Disable the safety backup during upgrade
|
help: Disable the safety backup during upgrade
|
||||||
action: store_true
|
action: store_true
|
||||||
-c:
|
|
||||||
full: --continue-on-failure
|
|
||||||
help: Continue to upgrade apps even if one or more upgrade failed
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### app_change_url()
|
### app_change_url()
|
||||||
change-url:
|
change-url:
|
||||||
|
@ -1021,18 +885,9 @@ app:
|
||||||
help: Delete the key
|
help: Delete the key
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
### app_shell()
|
|
||||||
shell:
|
|
||||||
action_help: Open an interactive shell with the app environment already loaded
|
|
||||||
# Here we set a GET only not to lock the command line. There is no actual API endpoint for app_shell()
|
|
||||||
api: GET /apps/<app>/shell
|
|
||||||
arguments:
|
|
||||||
app:
|
|
||||||
help: App ID
|
|
||||||
|
|
||||||
### app_register_url()
|
### app_register_url()
|
||||||
register-url:
|
register-url:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Book/register a web path for a given app
|
action_help: Book/register a web path for a given app
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
|
@ -1045,7 +900,6 @@ app:
|
||||||
|
|
||||||
### app_makedefault()
|
### app_makedefault()
|
||||||
makedefault:
|
makedefault:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Redirect domain root to an app
|
action_help: Redirect domain root to an app
|
||||||
api: PUT /apps/<app>/default
|
api: PUT /apps/<app>/default
|
||||||
arguments:
|
arguments:
|
||||||
|
@ -1054,21 +908,6 @@ app:
|
||||||
-d:
|
-d:
|
||||||
full: --domain
|
full: --domain
|
||||||
help: Specific domain to put app on (the app domain by default)
|
help: Specific domain to put app on (the app domain by default)
|
||||||
-u:
|
|
||||||
full: --undo
|
|
||||||
help: Undo redirection
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### app_dismiss_notification
|
|
||||||
dismiss-notification:
|
|
||||||
hide_in_help: True
|
|
||||||
action_help: Dismiss post_install or post_upgrade notification
|
|
||||||
api: PUT /apps/<app>/dismiss_notification/<name>
|
|
||||||
arguments:
|
|
||||||
app:
|
|
||||||
help: App ID to dismiss notification for
|
|
||||||
name:
|
|
||||||
help: Notification name, either post_install or post_upgrade
|
|
||||||
|
|
||||||
### app_ssowatconf()
|
### app_ssowatconf()
|
||||||
ssowatconf:
|
ssowatconf:
|
||||||
|
@ -1084,6 +923,36 @@ app:
|
||||||
new_label:
|
new_label:
|
||||||
help: New app label
|
help: New app label
|
||||||
|
|
||||||
|
### app_addaccess() TODO: Write help
|
||||||
|
addaccess:
|
||||||
|
action_help: Grant access right to users (everyone by default)
|
||||||
|
deprecated: true
|
||||||
|
arguments:
|
||||||
|
apps:
|
||||||
|
nargs: "+"
|
||||||
|
-u:
|
||||||
|
full: --users
|
||||||
|
nargs: "*"
|
||||||
|
|
||||||
|
### app_removeaccess() TODO: Write help
|
||||||
|
removeaccess:
|
||||||
|
action_help: Revoke access right to users (everyone by default)
|
||||||
|
deprecated: true
|
||||||
|
arguments:
|
||||||
|
apps:
|
||||||
|
nargs: "+"
|
||||||
|
-u:
|
||||||
|
full: --users
|
||||||
|
nargs: "*"
|
||||||
|
|
||||||
|
### app_clearaccess()
|
||||||
|
clearaccess:
|
||||||
|
action_help: Reset access rights for the app
|
||||||
|
deprecated: true
|
||||||
|
arguments:
|
||||||
|
apps:
|
||||||
|
nargs: "+"
|
||||||
|
|
||||||
subcategories:
|
subcategories:
|
||||||
|
|
||||||
action:
|
action:
|
||||||
|
@ -1118,9 +987,7 @@ app:
|
||||||
### app_config_get()
|
### app_config_get()
|
||||||
get:
|
get:
|
||||||
action_help: Display an app configuration
|
action_help: Display an app configuration
|
||||||
api:
|
api: GET /apps/<app>/config-panel
|
||||||
- GET /apps/<app>/config
|
|
||||||
- GET /apps/<app>/config/<key>
|
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
help: App name
|
help: App name
|
||||||
|
@ -1139,7 +1006,7 @@ app:
|
||||||
### app_config_set()
|
### app_config_set()
|
||||||
set:
|
set:
|
||||||
action_help: Apply a new configuration
|
action_help: Apply a new configuration
|
||||||
api: PUT /apps/<app>/config/<key>
|
api: PUT /apps/<app>/config
|
||||||
arguments:
|
arguments:
|
||||||
app:
|
app:
|
||||||
help: App name
|
help: App name
|
||||||
|
@ -1201,7 +1068,7 @@ backup:
|
||||||
api: PUT /backups/<name>/restore
|
api: PUT /backups/<name>/restore
|
||||||
arguments:
|
arguments:
|
||||||
name:
|
name:
|
||||||
help: Name or path of the backup archive
|
help: Name of the local backup archive
|
||||||
--system:
|
--system:
|
||||||
help: List of system parts to restore (or all if none is given)
|
help: List of system parts to restore (or all if none is given)
|
||||||
nargs: "*"
|
nargs: "*"
|
||||||
|
@ -1232,7 +1099,7 @@ backup:
|
||||||
api: GET /backups/<name>
|
api: GET /backups/<name>
|
||||||
arguments:
|
arguments:
|
||||||
name:
|
name:
|
||||||
help: Name or path of the backup archive
|
help: Name of the local backup archive
|
||||||
-d:
|
-d:
|
||||||
full: --with-details
|
full: --with-details
|
||||||
help: Show additional backup information
|
help: Show additional backup information
|
||||||
|
@ -1244,7 +1111,6 @@ backup:
|
||||||
|
|
||||||
### backup_download()
|
### backup_download()
|
||||||
download:
|
download:
|
||||||
hide_in_help: True
|
|
||||||
action_help: (API only) Request to download the file
|
action_help: (API only) Request to download the file
|
||||||
api: GET /backups/<name>/download
|
api: GET /backups/<name>/download
|
||||||
arguments:
|
arguments:
|
||||||
|
@ -1273,11 +1139,6 @@ settings:
|
||||||
list:
|
list:
|
||||||
action_help: list all entries of the settings
|
action_help: list all entries of the settings
|
||||||
api: GET /settings
|
api: GET /settings
|
||||||
arguments:
|
|
||||||
-f:
|
|
||||||
full: --full
|
|
||||||
help: Display all details (meant to be used by the API)
|
|
||||||
action: store_true
|
|
||||||
|
|
||||||
### settings_get()
|
### settings_get()
|
||||||
get:
|
get:
|
||||||
|
@ -1286,29 +1147,22 @@ settings:
|
||||||
arguments:
|
arguments:
|
||||||
key:
|
key:
|
||||||
help: Settings key
|
help: Settings key
|
||||||
-f:
|
--full:
|
||||||
full: --full
|
help: Show more details
|
||||||
help: Display all details (meant to be used by the API)
|
|
||||||
action: store_true
|
|
||||||
-e:
|
|
||||||
full: --export
|
|
||||||
help: Only export key/values, meant to be reimported using "config set --args-file"
|
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
### settings_set()
|
### settings_set()
|
||||||
set:
|
set:
|
||||||
action_help: set an entry value in the settings
|
action_help: set an entry value in the settings
|
||||||
api: PUT /settings/<key>
|
api: POST /settings/<key>
|
||||||
arguments:
|
arguments:
|
||||||
key:
|
key:
|
||||||
help: The question or form key
|
help: Settings key
|
||||||
nargs: '?'
|
|
||||||
-v:
|
-v:
|
||||||
full: --value
|
full: --value
|
||||||
help: new value
|
help: new value
|
||||||
-a:
|
extra:
|
||||||
full: --args
|
required: True
|
||||||
help: Serialized arguments for new configuration (i.e. "mail_in=0&mail_out=0")
|
|
||||||
|
|
||||||
### settings_reset_all()
|
### settings_reset_all()
|
||||||
reset-all:
|
reset-all:
|
||||||
|
@ -1343,6 +1197,13 @@ service:
|
||||||
full: --log
|
full: --log
|
||||||
help: Absolute path to log file to display
|
help: Absolute path to log file to display
|
||||||
nargs: "+"
|
nargs: "+"
|
||||||
|
-t:
|
||||||
|
full: --log_type
|
||||||
|
help: Type of the log (file or systemd)
|
||||||
|
nargs: "+"
|
||||||
|
choices:
|
||||||
|
- file
|
||||||
|
- systemd
|
||||||
--test_status:
|
--test_status:
|
||||||
help: Specify a custom bash command to check the status of the service. Note that it only makes sense to specify this if the corresponding systemd service does not return the proper information already.
|
help: Specify a custom bash command to check the status of the service. Note that it only makes sense to specify this if the corresponding systemd service does not return the proper information already.
|
||||||
--test_conf:
|
--test_conf:
|
||||||
|
@ -1356,6 +1217,9 @@ service:
|
||||||
full: --need_lock
|
full: --need_lock
|
||||||
help: Use this option to prevent deadlocks if the service does invoke yunohost commands.
|
help: Use this option to prevent deadlocks if the service does invoke yunohost commands.
|
||||||
action: store_true
|
action: store_true
|
||||||
|
-s:
|
||||||
|
full: --status
|
||||||
|
help: Deprecated, old option. Does nothing anymore. Possibly check the --test_status option.
|
||||||
|
|
||||||
### service_remove()
|
### service_remove()
|
||||||
remove:
|
remove:
|
||||||
|
@ -1457,6 +1321,35 @@ service:
|
||||||
default: 50
|
default: 50
|
||||||
type: int
|
type: int
|
||||||
|
|
||||||
|
### service_regen_conf()
|
||||||
|
regen-conf:
|
||||||
|
action_help: Regenerate the configuration file(s) for a service
|
||||||
|
deprecated_alias:
|
||||||
|
- regenconf
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Services name to regenerate configuration of
|
||||||
|
nargs: "*"
|
||||||
|
metavar: NAME
|
||||||
|
-d:
|
||||||
|
full: --with-diff
|
||||||
|
help: Show differences in case of configuration changes
|
||||||
|
action: store_true
|
||||||
|
-f:
|
||||||
|
full: --force
|
||||||
|
help: >
|
||||||
|
Override all manual modifications in configuration
|
||||||
|
files
|
||||||
|
action: store_true
|
||||||
|
-n:
|
||||||
|
full: --dry-run
|
||||||
|
help: Show what would have been regenerated
|
||||||
|
action: store_true
|
||||||
|
-p:
|
||||||
|
full: --list-pending
|
||||||
|
help: List pending configuration files and exit
|
||||||
|
action: store_true
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# Firewall #
|
# Firewall #
|
||||||
#############################
|
#############################
|
||||||
|
@ -1583,26 +1476,21 @@ firewall:
|
||||||
# DynDNS #
|
# DynDNS #
|
||||||
#############################
|
#############################
|
||||||
dyndns:
|
dyndns:
|
||||||
category_help: Subscribe and Update DynDNS Hosts ( deprecated, use 'yunohost domain dyndns' instead )
|
category_help: Subscribe and Update DynDNS Hosts
|
||||||
actions:
|
actions:
|
||||||
|
|
||||||
### dyndns_subscribe()
|
### dyndns_subscribe()
|
||||||
subscribe:
|
subscribe:
|
||||||
action_help: Subscribe to a DynDNS service
|
action_help: Subscribe to a DynDNS service
|
||||||
deprecated: true
|
|
||||||
arguments:
|
arguments:
|
||||||
-d:
|
-d:
|
||||||
full: --domain
|
full: --domain
|
||||||
help: Full domain to subscribe with ( deprecated, use 'yunohost domain dyndns subscribe' instead )
|
help: Full domain to subscribe with
|
||||||
extra:
|
extra:
|
||||||
pattern: *pattern_domain
|
pattern: *pattern_domain
|
||||||
-p:
|
-k:
|
||||||
full: --recovery-password
|
full: --key
|
||||||
nargs: "?"
|
help: Public DNS key
|
||||||
const: 0
|
|
||||||
help: Password used to later recover the domain if needed
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
|
|
||||||
### dyndns_update()
|
### dyndns_update()
|
||||||
update:
|
update:
|
||||||
|
@ -1622,6 +1510,14 @@ dyndns:
|
||||||
help: Only display the generated zone
|
help: Only display the generated zone
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
### dyndns_installcron()
|
||||||
|
installcron:
|
||||||
|
deprecated: true
|
||||||
|
|
||||||
|
### dyndns_removecron()
|
||||||
|
removecron:
|
||||||
|
deprecated: true
|
||||||
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# Tools #
|
# Tools #
|
||||||
|
@ -1630,10 +1526,10 @@ tools:
|
||||||
category_help: Specific tools
|
category_help: Specific tools
|
||||||
actions:
|
actions:
|
||||||
|
|
||||||
### tools_rootpw()
|
### tools_adminpw()
|
||||||
rootpw:
|
adminpw:
|
||||||
action_help: Change root password
|
action_help: Change password of admin and root users
|
||||||
api: PUT /rootpw
|
api: PUT /adminpw
|
||||||
arguments:
|
arguments:
|
||||||
-n:
|
-n:
|
||||||
full: --new-password
|
full: --new-password
|
||||||
|
@ -1668,20 +1564,6 @@ tools:
|
||||||
ask: ask_main_domain
|
ask: ask_main_domain
|
||||||
pattern: *pattern_domain
|
pattern: *pattern_domain
|
||||||
required: True
|
required: True
|
||||||
-u:
|
|
||||||
full: --username
|
|
||||||
help: Username for the first (admin) user. For example 'camille'
|
|
||||||
extra:
|
|
||||||
ask: ask_admin_username
|
|
||||||
pattern: *pattern_username
|
|
||||||
required: True
|
|
||||||
-F:
|
|
||||||
full: --fullname
|
|
||||||
help: The full name for the first (admin) user. For example 'Camille Dupont'
|
|
||||||
extra:
|
|
||||||
ask: ask_admin_fullname
|
|
||||||
required: True
|
|
||||||
pattern: *pattern_fullname
|
|
||||||
-p:
|
-p:
|
||||||
full: --password
|
full: --password
|
||||||
help: YunoHost admin password
|
help: YunoHost admin password
|
||||||
|
@ -1691,19 +1573,16 @@ tools:
|
||||||
required: True
|
required: True
|
||||||
comment: good_practices_about_admin_password
|
comment: good_practices_about_admin_password
|
||||||
--ignore-dyndns:
|
--ignore-dyndns:
|
||||||
help: If adding a DynDNS domain, only add the domain, without subscribing to the DynDNS service
|
help: Do not subscribe domain to a DynDNS service
|
||||||
|
action: store_true
|
||||||
|
--force-password:
|
||||||
|
help: Use this if you really want to set a weak password
|
||||||
action: store_true
|
action: store_true
|
||||||
--dyndns-recovery-password:
|
|
||||||
metavar: PASSWORD
|
|
||||||
nargs: "?"
|
|
||||||
const: 0
|
|
||||||
help: If adding a DynDNS domain, subscribe to the DynDNS service with a password, used to later recover the domain if needed
|
|
||||||
extra:
|
|
||||||
pattern: *pattern_password
|
|
||||||
--force-diskspace:
|
--force-diskspace:
|
||||||
help: Use this if you really want to install YunoHost on a setup with less than 10 GB on the root filesystem
|
help: Use this if you really want to install YunoHost on a setup with less than 10 GB on the root filesystem
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
|
||||||
### tools_update()
|
### tools_update()
|
||||||
update:
|
update:
|
||||||
action_help: YunoHost update
|
action_help: YunoHost update
|
||||||
|
@ -1718,6 +1597,12 @@ tools:
|
||||||
nargs: "?"
|
nargs: "?"
|
||||||
metavar: TARGET
|
metavar: TARGET
|
||||||
default: all
|
default: all
|
||||||
|
--apps:
|
||||||
|
help: (Deprecated, see first positional arg) Fetch the application list to check which apps can be upgraded
|
||||||
|
action: store_true
|
||||||
|
--system:
|
||||||
|
help: (Deprecated, see first positional arg) Fetch available system packages upgrades (equivalent to apt update)
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### tools_upgrade()
|
### tools_upgrade()
|
||||||
upgrade:
|
upgrade:
|
||||||
|
@ -1730,6 +1615,12 @@ tools:
|
||||||
- apps
|
- apps
|
||||||
- system
|
- system
|
||||||
nargs: "?"
|
nargs: "?"
|
||||||
|
--apps:
|
||||||
|
help: (Deprecated, see first positional arg) Upgrade all applications
|
||||||
|
action: store_true
|
||||||
|
--system:
|
||||||
|
help: (Deprecated, see first positional arg) Upgrade only the system packages
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### tools_shell()
|
### tools_shell()
|
||||||
shell:
|
shell:
|
||||||
|
@ -1739,10 +1630,6 @@ tools:
|
||||||
help: python command to execute
|
help: python command to execute
|
||||||
full: --command
|
full: --command
|
||||||
|
|
||||||
### tools_basic_space_cleanup()
|
|
||||||
basic-space-cleanup:
|
|
||||||
action_help: Basic space cleanup (apt, journalctl, logs, ...)
|
|
||||||
|
|
||||||
### tools_shutdown()
|
### tools_shutdown()
|
||||||
shutdown:
|
shutdown:
|
||||||
action_help: Shutdown the server
|
action_help: Shutdown the server
|
||||||
|
@ -1869,7 +1756,6 @@ hook:
|
||||||
|
|
||||||
### hook_info()
|
### hook_info()
|
||||||
info:
|
info:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Get information about a given hook
|
action_help: Get information about a given hook
|
||||||
arguments:
|
arguments:
|
||||||
action:
|
action:
|
||||||
|
@ -1899,7 +1785,6 @@ hook:
|
||||||
|
|
||||||
### hook_callback()
|
### hook_callback()
|
||||||
callback:
|
callback:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Execute all scripts binded to an action
|
action_help: Execute all scripts binded to an action
|
||||||
arguments:
|
arguments:
|
||||||
action:
|
action:
|
||||||
|
@ -1922,7 +1807,6 @@ hook:
|
||||||
|
|
||||||
### hook_exec()
|
### hook_exec()
|
||||||
exec:
|
exec:
|
||||||
hide_in_help: True
|
|
||||||
action_help: Execute hook from a file with arguments
|
action_help: Execute hook from a file with arguments
|
||||||
arguments:
|
arguments:
|
||||||
path:
|
path:
|
||||||
|
@ -1976,7 +1860,7 @@ log:
|
||||||
- display
|
- display
|
||||||
arguments:
|
arguments:
|
||||||
path:
|
path:
|
||||||
help: Log file which to display the content. 'last' or 'last-X' selects the last but X log file
|
help: Log file which to display the content
|
||||||
-n:
|
-n:
|
||||||
full: --number
|
full: --number
|
||||||
help: Number of lines to display
|
help: Number of lines to display
|
||||||
|
@ -2079,6 +1963,6 @@ diagnosis:
|
||||||
api: PUT /diagnosis/unignore
|
api: PUT /diagnosis/unignore
|
||||||
arguments:
|
arguments:
|
||||||
--filter:
|
--filter:
|
||||||
help: Remove a filter (it should be an existing filter as listed with "ignore --list")
|
help: Remove a filter (it should be an existing filter as listed with --list)
|
||||||
nargs: "*"
|
nargs: "*"
|
||||||
metavar: CRITERIA
|
metavar: CRITERIA
|
|
@ -8,14 +8,13 @@ adds `--help` at the end if one presses [tab] again.
|
||||||
|
|
||||||
author: Christophe Vuillot
|
author: Christophe Vuillot
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/../share/actionsmap.yml"
|
ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/yunohost.yml"
|
||||||
BASH_COMPLETION_FOLDER = THIS_SCRIPT_DIR + "/bash_completion.d"
|
os.system(f"mkdir {THIS_SCRIPT_DIR}/../bash-completion.d")
|
||||||
BASH_COMPLETION_FILE = BASH_COMPLETION_FOLDER + "/yunohost"
|
BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost"
|
||||||
|
|
||||||
|
|
||||||
def get_dict_actions(OPTION_SUBTREE, category):
|
def get_dict_actions(OPTION_SUBTREE, category):
|
||||||
|
@ -32,6 +31,7 @@ def get_dict_actions(OPTION_SUBTREE, category):
|
||||||
|
|
||||||
|
|
||||||
with open(ACTIONSMAP_FILE, "r") as stream:
|
with open(ACTIONSMAP_FILE, "r") as stream:
|
||||||
|
|
||||||
# Getting the dictionary containning what actions are possible per category
|
# Getting the dictionary containning what actions are possible per category
|
||||||
OPTION_TREE = yaml.safe_load(stream)
|
OPTION_TREE = yaml.safe_load(stream)
|
||||||
|
|
||||||
|
@ -62,9 +62,8 @@ with open(ACTIONSMAP_FILE, "r") as stream:
|
||||||
OPTION_TREE[category]["subcategories"], subcategory
|
OPTION_TREE[category]["subcategories"], subcategory
|
||||||
)
|
)
|
||||||
|
|
||||||
os.makedirs(BASH_COMPLETION_FOLDER, exist_ok=True)
|
|
||||||
|
|
||||||
with open(BASH_COMPLETION_FILE, "w") as generated_file:
|
with open(BASH_COMPLETION_FILE, "w") as generated_file:
|
||||||
|
|
||||||
# header of the file
|
# header of the file
|
||||||
generated_file.write("#\n")
|
generated_file.write("#\n")
|
||||||
generated_file.write("# completion for yunohost\n")
|
generated_file.write("# completion for yunohost\n")
|
8
data/helpers
Normal file
8
data/helpers
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# -*- shell-script -*-
|
||||||
|
|
||||||
|
readonly XTRACE_ENABLE=$(set +o | grep xtrace) # This is a trick to later only restore set -x if it was set when calling this script
|
||||||
|
set +x
|
||||||
|
for helper in $(run-parts --list /usr/share/yunohost/helpers.d 2>/dev/null) ; do
|
||||||
|
[ -r $helper ] && . $helper || true
|
||||||
|
done
|
||||||
|
eval "$XTRACE_ENABLE"
|
|
@ -58,6 +58,7 @@ ynh_package_is_installed() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
ynh_wait_dpkg_free
|
||||||
dpkg-query --show --showformat='${Status}' "$package" 2>/dev/null \
|
dpkg-query --show --showformat='${Status}' "$package" 2>/dev/null \
|
||||||
| grep --count "ok installed" &>/dev/null
|
| grep --count "ok installed" &>/dev/null
|
||||||
}
|
}
|
||||||
|
@ -66,8 +67,6 @@ ynh_package_is_installed() {
|
||||||
#
|
#
|
||||||
# example: version=$(ynh_package_version --package=yunohost)
|
# example: version=$(ynh_package_version --package=yunohost)
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_version --package=name
|
# usage: ynh_package_version --package=name
|
||||||
# | arg: -p, --package= - the package name to get version
|
# | arg: -p, --package= - the package name to get version
|
||||||
# | ret: the version or an empty string
|
# | ret: the version or an empty string
|
||||||
|
@ -102,8 +101,6 @@ ynh_apt() {
|
||||||
|
|
||||||
# Update package index files
|
# Update package index files
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_update
|
# usage: ynh_package_update
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
|
@ -113,8 +110,6 @@ ynh_package_update() {
|
||||||
|
|
||||||
# Install package(s)
|
# Install package(s)
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_install name [name [...]]
|
# usage: ynh_package_install name [name [...]]
|
||||||
# | arg: name - the package name to install
|
# | arg: name - the package name to install
|
||||||
#
|
#
|
||||||
|
@ -126,8 +121,6 @@ ynh_package_install() {
|
||||||
|
|
||||||
# Remove package(s)
|
# Remove package(s)
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_remove name [name [...]]
|
# usage: ynh_package_remove name [name [...]]
|
||||||
# | arg: name - the package name to remove
|
# | arg: name - the package name to remove
|
||||||
#
|
#
|
||||||
|
@ -138,8 +131,6 @@ ynh_package_remove() {
|
||||||
|
|
||||||
# Remove package(s) and their uneeded dependencies
|
# Remove package(s) and their uneeded dependencies
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_autoremove name [name [...]]
|
# usage: ynh_package_autoremove name [name [...]]
|
||||||
# | arg: name - the package name to remove
|
# | arg: name - the package name to remove
|
||||||
#
|
#
|
||||||
|
@ -150,8 +141,6 @@ ynh_package_autoremove() {
|
||||||
|
|
||||||
# Purge package(s) and their uneeded dependencies
|
# Purge package(s) and their uneeded dependencies
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_package_autopurge name [name [...]]
|
# usage: ynh_package_autopurge name [name [...]]
|
||||||
# | arg: name - the package name to autoremove and purge
|
# | arg: name - the package name to autoremove and purge
|
||||||
#
|
#
|
||||||
|
@ -186,25 +175,21 @@ ynh_package_install_from_equivs() {
|
||||||
|
|
||||||
# Build and install the package
|
# Build and install the package
|
||||||
local TMPDIR=$(mktemp --directory)
|
local TMPDIR=$(mktemp --directory)
|
||||||
mkdir -p ${TMPDIR}/${pkgname}/DEBIAN/
|
|
||||||
# For some reason, dpkg-deb insists for folder perm to be 755 and sometimes it's 777 o_O?
|
# Force the compatibility level at 10, levels below are deprecated
|
||||||
chmod -R 755 ${TMPDIR}/${pkgname}
|
echo 10 >/usr/share/equivs/template/debian/compat
|
||||||
|
|
||||||
# Note that the cd executes into a sub shell
|
# Note that the cd executes into a sub shell
|
||||||
# Create a fake deb package with equivs-build and the given control file
|
# Create a fake deb package with equivs-build and the given control file
|
||||||
# Install the fake package without its dependencies with dpkg
|
# Install the fake package without its dependencies with dpkg
|
||||||
# Install missing dependencies with ynh_package_install
|
# Install missing dependencies with ynh_package_install
|
||||||
ynh_wait_dpkg_free
|
ynh_wait_dpkg_free
|
||||||
|
cp "$controlfile" "${TMPDIR}/control"
|
||||||
cp "$controlfile" "${TMPDIR}/${pkgname}/DEBIAN/control"
|
(
|
||||||
|
cd "$TMPDIR"
|
||||||
# Install the fake package without its dependencies with dpkg --force-depends
|
LC_ALL=C equivs-build ./control 1>/dev/null
|
||||||
if ! LC_ALL=C dpkg-deb --build "${TMPDIR}/${pkgname}" "${TMPDIR}/${pkgname}.deb" > "${TMPDIR}/dpkg_log" 2>&1; then
|
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log
|
||||||
cat "${TMPDIR}/dpkg_log" >&2
|
)
|
||||||
ynh_die --message="Unable to install dependencies"
|
|
||||||
fi
|
|
||||||
# Don't crash in case of error, because is nicely covered by the following line
|
|
||||||
LC_ALL=C dpkg --force-depends --install "${TMPDIR}/${pkgname}.deb" 2>&1 | tee "${TMPDIR}/dpkg_log" || true
|
|
||||||
|
|
||||||
ynh_package_install --fix-broken \
|
ynh_package_install --fix-broken \
|
||||||
|| { # If the installation failed
|
|| { # If the installation failed
|
||||||
|
@ -241,8 +226,9 @@ ynh_install_app_dependencies() {
|
||||||
# Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below)
|
# Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below)
|
||||||
dependencies="$(echo "$dependencies" | sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g')"
|
dependencies="$(echo "$dependencies" | sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g')"
|
||||||
local dependencies=${dependencies//|/ | }
|
local dependencies=${dependencies//|/ | }
|
||||||
|
local manifest_path="$YNH_APP_BASEDIR/manifest.json"
|
||||||
|
|
||||||
local version=$(ynh_read_manifest --manifest_key="version")
|
local version=$(jq -r '.version' "$manifest_path")
|
||||||
if [ -z "${version}" ] || [ "$version" == "null" ]; then
|
if [ -z "${version}" ] || [ "$version" == "null" ]; then
|
||||||
version="1.0"
|
version="1.0"
|
||||||
fi
|
fi
|
||||||
|
@ -264,15 +250,77 @@ ynh_install_app_dependencies() {
|
||||||
# Check for specific php dependencies which requires sury
|
# 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"
|
# This grep will for example return "7.4" if dependencies is "foo bar php7.4-pwet php-gni"
|
||||||
# The (?<=php) syntax corresponds to lookbehind ;)
|
# 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
|
# Ignore case where the php version found is the one available in debian vanilla
|
||||||
|
[[ "$specific_php_version" != "$YNH_DEFAULT_PHP_VERSION" ]] || specific_php_version=""
|
||||||
|
|
||||||
|
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
|
# 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 ]] \
|
[[ $(echo $specific_php_version | wc -l) -eq 1 ]] \
|
||||||
|| ynh_die --message="Inconsistent php versions in dependencies ... found : $specific_php_version"
|
|| ynh_die --message="Inconsistent php versions in dependencies ... found : $specific_php_version"
|
||||||
|
|
||||||
dependencies+=", php${specific_php_version}, php${specific_php_version}-fpm, php${specific_php_version}-common"
|
dependencies+=", php${specific_php_version}, php${specific_php_version}-fpm, php${specific_php_version}-common"
|
||||||
|
|
||||||
|
ynh_add_sury
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# 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_INSTALL_APP_DEPENDENCIES_REPLACE == "true" ]]
|
||||||
|
then
|
||||||
|
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="false"
|
||||||
|
else
|
||||||
|
local current_dependencies=""
|
||||||
|
if ynh_package_is_installed --package="${dep_app}-ynh-deps"
|
||||||
|
then
|
||||||
|
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
|
||||||
|
current_dependencies=${current_dependencies// | /|}
|
||||||
|
fi
|
||||||
|
dependencies="$current_dependencies, $dependencies"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Epic ugly hack to fix the goddamn dependency nightmare of sury
|
||||||
|
# Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective
|
||||||
|
# https://github.com/YunoHost/issues/issues/1407
|
||||||
|
#
|
||||||
|
# If we require to install php dependency
|
||||||
|
if grep --quiet 'php' <<< "$dependencies"; then
|
||||||
|
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
|
||||||
|
if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9"; then
|
||||||
|
# And sury ain't already in sources.lists
|
||||||
|
if ! grep --recursive --quiet "^ *deb.*sury" /etc/apt/sources.list*; then
|
||||||
|
# Re-add sury
|
||||||
|
ynh_add_sury
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >/tmp/${dep_app}-ynh-deps.control <<EOF # Make a control file for equivs-build
|
||||||
|
Section: misc
|
||||||
|
Priority: optional
|
||||||
|
Package: ${dep_app}-ynh-deps
|
||||||
|
Version: ${version}
|
||||||
|
Depends: ${dependencies}
|
||||||
|
Architecture: all
|
||||||
|
Description: Fake package for ${app} (YunoHost app) dependencies
|
||||||
|
This meta-package is only responsible of installing its dependencies.
|
||||||
|
EOF
|
||||||
|
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \
|
||||||
|
|| ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
|
||||||
|
rm /tmp/${dep_app}-ynh-deps.control
|
||||||
|
|
||||||
|
if [[ -n "$specific_php_version" ]]
|
||||||
|
then
|
||||||
|
# Set the default php version back as the default version for php-cli.
|
||||||
|
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
||||||
|
|
||||||
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
||||||
|
|
||||||
# If the PHP version changed, remove the old fpm conf
|
# If the PHP version changed, remove the old fpm conf
|
||||||
|
@ -280,68 +328,40 @@ ynh_install_app_dependencies() {
|
||||||
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
||||||
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
||||||
|
|
||||||
if [[ -f "$old_php_finalphpconf" ]]; then
|
if [[ -f "$old_php_finalphpconf" ]]
|
||||||
|
then
|
||||||
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
|
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
|
||||||
ynh_remove_fpm_config
|
ynh_remove_fpm_config
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Store phpversion into the config of this app
|
# Store phpversion into the config of this app
|
||||||
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
|
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
|
||||||
|
|
||||||
# Set the default php version back as the default version for php-cli.
|
# Integrate new php-fpm service in yunohost
|
||||||
if test -e /usr/bin/php$YNH_DEFAULT_PHP_VERSION; then
|
yunohost service add php${specific_php_version}-fpm --log "/var/log/php${specific_php_version}-fpm.log"
|
||||||
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
|
||||||
fi
|
|
||||||
elif grep --quiet 'php' <<< "$dependencies"; then
|
elif grep --quiet 'php' <<< "$dependencies"; then
|
||||||
|
# Store phpversion into the config of this app
|
||||||
ynh_app_setting_set --app=$app --key=phpversion --value=$YNH_DEFAULT_PHP_VERSION
|
ynh_app_setting_set --app=$app --key=phpversion --value=$YNH_DEFAULT_PHP_VERSION
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
local psql_installed="$(ynh_package_is_installed "postgresql-$PSQL_VERSION" && echo yes || echo no)"
|
# Add sury repository with adequate pin strategy
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_add_sury
|
||||||
|
#
|
||||||
|
ynh_add_sury() {
|
||||||
|
|
||||||
# The first time we run ynh_install_app_dependencies, we will replace the
|
# Add an extra repository for those packages
|
||||||
# entire control file (This is in particular meant to cover the case of
|
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version --priority=600
|
||||||
# upgrade script where ynh_install_app_dependencies is called with this
|
|
||||||
# expected effect) Otherwise, any subsequent call will add dependencies
|
|
||||||
# to those already present in the equivs control file.
|
|
||||||
if [[ $YNH_INSTALL_APP_DEPENDENCIES_REPLACE == "true" ]]; then
|
|
||||||
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="false"
|
|
||||||
else
|
|
||||||
local current_dependencies=""
|
|
||||||
if ynh_package_is_installed --package="${dep_app}-ynh-deps"; then
|
|
||||||
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
|
|
||||||
current_dependencies=${current_dependencies// | /|}
|
|
||||||
fi
|
|
||||||
dependencies="$current_dependencies, $dependencies"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build
|
|
||||||
Section: misc
|
|
||||||
Priority: optional
|
|
||||||
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
|
|
||||||
|
|
||||||
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \
|
|
||||||
|| ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
|
|
||||||
rm /tmp/${dep_app}-ynh-deps.control
|
|
||||||
|
|
||||||
# Trigger postgresql regenconf if we may have just installed postgresql
|
|
||||||
local psql_installed2="$(ynh_package_is_installed "postgresql-$PSQL_VERSION" && echo yes || echo no)"
|
|
||||||
if [[ "$psql_installed" != "$psql_installed2" ]]; then
|
|
||||||
yunohost tools regen-conf postgresql
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Add dependencies to install with ynh_install_app_dependencies
|
# Add dependencies to install with ynh_install_app_dependencies
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
||||||
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
||||||
#
|
#
|
||||||
|
@ -376,15 +396,21 @@ ynh_remove_app_dependencies() {
|
||||||
|
|
||||||
# Edge case where the app dep may be on hold,
|
# Edge case where the app dep may be on hold,
|
||||||
# cf https://forum.yunohost.org/t/migration-error-cause-of-ffsync/20675/4
|
# cf https://forum.yunohost.org/t/migration-error-cause-of-ffsync/20675/4
|
||||||
if apt-mark showhold | grep -q -w ${dep_app}-ynh-deps; then
|
if apt-mark showhold | grep -q -w ${dep_app}-ynh-deps
|
||||||
|
then
|
||||||
apt-mark unhold ${dep_app}-ynh-deps
|
apt-mark unhold ${dep_app}-ynh-deps
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove the fake package and its dependencies if they not still used.
|
ynh_package_autopurge ${dep_app}-ynh-deps # 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)
|
# Check if this app used a specific php version ... in which case we check
|
||||||
if dpkg-query --show ${dep_app}-ynh-deps &> /dev/null; then
|
# if the corresponding php-fpm is still there. Otherwise, we remove the
|
||||||
ynh_package_autopurge ${dep_app}-ynh-deps
|
# service from yunohost as well
|
||||||
|
|
||||||
|
local specific_php_version=$(echo $current_dependencies | tr '-' ' ' | grep -o -E "\<php[0-9.]+\>" | sed 's/php//g' | sort | uniq)
|
||||||
|
[[ "$specific_php_version" != "$YNH_DEFAULT_PHP_VERSION" ]] || specific_php_version=""
|
||||||
|
if [[ -n "$specific_php_version" ]] && ! ynh_package_is_installed --package="php${specific_php_version}-fpm"; then
|
||||||
|
yunohost service remove php${specific_php_version}-fpm
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +453,7 @@ ynh_install_extra_app_dependencies() {
|
||||||
[ -z "$apps_auto_installed" ] || apt-mark auto $apps_auto_installed
|
[ -z "$apps_auto_installed" ] || apt-mark auto $apps_auto_installed
|
||||||
|
|
||||||
# Remove this extra repository after packages are installed
|
# Remove this extra repository after packages are installed
|
||||||
ynh_remove_extra_repo --name=$name
|
ynh_remove_extra_repo --name=$app
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add an extra repository correctly, pin it and get the key.
|
# Add an extra repository correctly, pin it and get the key.
|
||||||
|
@ -466,31 +492,21 @@ ynh_install_extra_repo() {
|
||||||
wget_append="tee"
|
wget_append="tee"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$key" == "trusted=yes" ]]; then
|
# Split the repository into uri, suite and components.
|
||||||
trusted="--trusted"
|
|
||||||
else
|
|
||||||
trusted=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
IFS=', ' read -r -a repo_parts <<< "$repo"
|
|
||||||
index=0
|
|
||||||
|
|
||||||
# Remove "deb " at the beginning of the repo.
|
# Remove "deb " at the beginning of the repo.
|
||||||
if [[ "${repo_parts[0]}" == "deb" ]]; then
|
repo="${repo#deb }"
|
||||||
index=1
|
|
||||||
fi
|
# Get the uri
|
||||||
uri="${repo_parts[$index]}"
|
local uri="$(echo "$repo" | awk '{ print $1 }')"
|
||||||
index=$((index + 1))
|
|
||||||
suite="${repo_parts[$index]}"
|
# Get the suite
|
||||||
index=$((index + 1))
|
local suite="$(echo "$repo" | awk '{ print $2 }')"
|
||||||
|
|
||||||
# Get the components
|
# Get the components
|
||||||
if (("${#repo_parts[@]}" > 0)); then
|
local component="${repo##$uri $suite }"
|
||||||
component="${repo_parts[*]:$index}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add the repository into sources.list.d
|
# Add the repository into sources.list.d
|
||||||
ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append $trusted
|
ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append
|
||||||
|
|
||||||
# Pin the new repo with the default priority, so it won't be used for upgrades.
|
# 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
|
# Build $pin from the uri without http and any sub path
|
||||||
|
@ -503,7 +519,7 @@ ynh_install_extra_repo() {
|
||||||
ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append
|
ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append
|
||||||
|
|
||||||
# Get the public key for the repo
|
# Get the public key for the repo
|
||||||
if [ -n "$key" ] && [[ "$key" != "trusted=yes" ]]; then
|
if [ -n "$key" ]; then
|
||||||
mkdir --parents "/etc/apt/trusted.gpg.d"
|
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)
|
# 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
|
wget --timeout 900 --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg >/dev/null
|
||||||
|
@ -533,14 +549,8 @@ ynh_remove_extra_repo() {
|
||||||
ynh_secure_remove --file="/etc/apt/sources.list.d/$name.list"
|
ynh_secure_remove --file="/etc/apt/sources.list.d/$name.list"
|
||||||
# Sury pinning is managed by the regenconf in the core...
|
# Sury pinning is managed by the regenconf in the core...
|
||||||
[[ "$name" == "extra_php_version" ]] || ynh_secure_remove "/etc/apt/preferences.d/$name"
|
[[ "$name" == "extra_php_version" ]] || ynh_secure_remove "/etc/apt/preferences.d/$name"
|
||||||
if [ -e /etc/apt/trusted.gpg.d/$name.gpg ]; then
|
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.gpg" >/dev/null
|
||||||
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.gpg"
|
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.asc" >/dev/null
|
||||||
fi
|
|
||||||
|
|
||||||
# (Do we even create a .asc file anywhere ...?)
|
|
||||||
if [ -e /etc/apt/trusted.gpg.d/$name.asc ]; then
|
|
||||||
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.asc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update the list of package to exclude the old repo
|
# Update the list of package to exclude the old repo
|
||||||
ynh_package_update
|
ynh_package_update
|
||||||
|
@ -556,7 +566,6 @@ ynh_remove_extra_repo() {
|
||||||
# | arg: -c, --component= - Component of the repository.
|
# | arg: -c, --component= - Component of the repository.
|
||||||
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
# | arg: -a, --append - Do not overwrite existing files.
|
# | 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
|
# Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable
|
||||||
# uri suite component
|
# uri suite component
|
||||||
|
@ -565,34 +574,27 @@ ynh_remove_extra_repo() {
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_add_repo() {
|
ynh_add_repo() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uscnat
|
local legacy_args=uscna
|
||||||
local -A args_array=([u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append [t]=trusted)
|
local -A args_array=([u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append)
|
||||||
local uri
|
local uri
|
||||||
local suite
|
local suite
|
||||||
local component
|
local component
|
||||||
local name
|
local name
|
||||||
local append
|
local append
|
||||||
local trusted
|
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
name="${name:-$app}"
|
name="${name:-$app}"
|
||||||
append=${append:-0}
|
append=${append:-0}
|
||||||
trusted=${trusted:-0}
|
|
||||||
|
|
||||||
if [ $append -eq 1 ]; then
|
if [ $append -eq 1 ]; then
|
||||||
append="tee --append"
|
append="tee --append"
|
||||||
else
|
else
|
||||||
append="tee"
|
append="tee"
|
||||||
fi
|
fi
|
||||||
if [[ "$trusted" -eq 1 ]]; then
|
|
||||||
trust="[trusted=yes]"
|
|
||||||
else
|
|
||||||
trust=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir --parents "/etc/apt/sources.list.d"
|
mkdir --parents "/etc/apt/sources.list.d"
|
||||||
# Add the new repo in sources.list.d
|
# Add the new repo in sources.list.d
|
||||||
echo "deb $trust $uri $suite $component" \
|
echo "deb $uri $suite $component" \
|
||||||
| $append "/etc/apt/sources.list.d/$name.list"
|
| $append "/etc/apt/sources.list.d/$name.list"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
# | arg: -d, --dest_path= - destination file or directory inside the backup dir
|
# | arg: -d, --dest_path= - destination file or directory inside the backup dir
|
||||||
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
|
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
|
||||||
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
|
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
|
||||||
|
# | arg: arg - Deprecated arg
|
||||||
#
|
#
|
||||||
# This helper can be used both in a system backup hook, and in an app backup script
|
# This helper can be used both in a system backup hook, and in an app backup script
|
||||||
#
|
#
|
||||||
|
@ -226,7 +227,7 @@ with open(sys.argv[1], 'r') as backup_file:
|
||||||
# ynh_restore_file -o "conf/nginx.conf"
|
# ynh_restore_file -o "conf/nginx.conf"
|
||||||
#
|
#
|
||||||
# If `DEST_PATH` already exists and is lighter than 500 Mo, a backup will be made in
|
# If `DEST_PATH` already exists and is lighter than 500 Mo, a backup will be made in
|
||||||
# `/var/cache/yunohost/appconfbackup/`. Otherwise, the existing file is removed.
|
# `/home/yunohost.conf/backup/`. Otherwise, the existing file is removed.
|
||||||
#
|
#
|
||||||
# if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into
|
# if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into
|
||||||
# `/etc/nginx/conf.d/$domain.d/$app.conf`
|
# `/etc/nginx/conf.d/$domain.d/$app.conf`
|
||||||
|
@ -263,7 +264,7 @@ ynh_restore_file() {
|
||||||
if [[ -e "${dest_path}" ]]; then
|
if [[ -e "${dest_path}" ]]; then
|
||||||
# Check if the file/dir size is less than 500 Mo
|
# Check if the file/dir size is less than 500 Mo
|
||||||
if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]; then
|
if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]; then
|
||||||
local backup_file="/var/cache/yunohost/appconfbackup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
mkdir --parents "$(dirname "$backup_file")"
|
mkdir --parents "$(dirname "$backup_file")"
|
||||||
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
||||||
else
|
else
|
||||||
|
@ -285,13 +286,18 @@ ynh_restore_file() {
|
||||||
else
|
else
|
||||||
mv "$archive_path" "${dest_path}"
|
mv "$archive_path" "${dest_path}"
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Boring hack for nginx conf file mapped to php7.3
|
# Deprecated helper since it's a dangerous one!
|
||||||
# Note that there's no need to patch the fpm config because most php apps
|
#
|
||||||
# will call "ynh_add_fpm_config" during restore, effectively recreating the file from scratch
|
# [internal]
|
||||||
if [[ "${dest_path}" == "/etc/nginx/conf.d/"* ]] && grep 'php7.3.*sock' "${dest_path}"; then
|
#
|
||||||
sed -i 's/php7.3/php7.4/g' "${dest_path}"
|
ynh_bind_or_cp() {
|
||||||
fi
|
local AS_ROOT=${3:-0}
|
||||||
|
local NO_ROOT=0
|
||||||
|
[[ "${AS_ROOT}" = "1" ]] || NO_ROOT=1
|
||||||
|
ynh_print_warn --message="This helper is deprecated, you should use ynh_backup instead"
|
||||||
|
ynh_backup "$1" "$2" 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Calculate and store a file checksum into the app settings
|
# Calculate and store a file checksum into the app settings
|
||||||
|
@ -326,13 +332,6 @@ ynh_store_file_checksum() {
|
||||||
|
|
||||||
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
||||||
|
|
||||||
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; 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 backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
||||||
if [ -n "${backup_file_checksum-}" ]; then
|
if [ -n "${backup_file_checksum-}" ]; then
|
||||||
# Print the diff between the previous file and the new one.
|
# Print the diff between the previous file and the new one.
|
||||||
|
@ -367,19 +366,11 @@ ynh_backup_if_checksum_is_different() {
|
||||||
backup_file_checksum=""
|
backup_file_checksum=""
|
||||||
if [ -n "$checksum_value" ]; then # Proceed only if a value was stored into the app settings
|
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
|
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status; then # If the checksum is now different
|
||||||
|
backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
backup_file_checksum="/var/cache/yunohost/appconfbackup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
|
||||||
mkdir --parents "$(dirname "$backup_file_checksum")"
|
mkdir --parents "$(dirname "$backup_file_checksum")"
|
||||||
cp --archive "$file" "$backup_file_checksum" # Backup the current file
|
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"
|
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
|
echo "$backup_file_checksum" # Return the name of the backup file
|
||||||
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
|
|
||||||
local file_path_base64=$(echo "$file" | base64 -w0)
|
|
||||||
if test -e /var/cache/yunohost/appconfbackup/original_${file_path_base64}; then
|
|
||||||
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
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -415,8 +406,6 @@ ynh_backup_archive_exists() {
|
||||||
|
|
||||||
# Make a backup in case of failed upgrade
|
# Make a backup in case of failed upgrade
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_backup_before_upgrade
|
# usage: ynh_backup_before_upgrade
|
||||||
#
|
#
|
||||||
# Usage in a package script:
|
# Usage in a package script:
|
||||||
|
@ -465,8 +454,6 @@ ynh_backup_before_upgrade() {
|
||||||
|
|
||||||
# Restore a previous backup if the upgrade process failed
|
# Restore a previous backup if the upgrade process failed
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_restore_upgradebackup
|
# usage: ynh_restore_upgradebackup
|
||||||
#
|
#
|
||||||
# Usage in a package script:
|
# Usage in a package script:
|
||||||
|
@ -492,7 +479,8 @@ ynh_restore_upgradebackup() {
|
||||||
yunohost app remove $app
|
yunohost app remove $app
|
||||||
# Restore the backup
|
# Restore the backup
|
||||||
yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
|
yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
|
||||||
if [[ -d /etc/yunohost/apps/$app ]]; then
|
if [[ -d /etc/yunohost/apps/$app ]]
|
||||||
|
then
|
||||||
ynh_die --message="The app was restored to the way it was before the failed upgrade."
|
ynh_die --message="The app was restored to the way it was before the failed upgrade."
|
||||||
else
|
else
|
||||||
ynh_die --message="Uhoh ... Yunohost failed to restore the app to the way it was before the failed upgrade :|"
|
ynh_die --message="Uhoh ... Yunohost failed to restore the app to the way it was before the failed upgrade :|"
|
|
@ -22,7 +22,7 @@ _ynh_app_config_get_one() {
|
||||||
if [[ "$bind" == "settings" ]]; then
|
if [[ "$bind" == "settings" ]]; then
|
||||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||||
fi
|
fi
|
||||||
old[$short_setting]="$(ls "$bind" 2> /dev/null || echo YNH_NULL)"
|
old[$short_setting]="$(ls "$(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)" 2>/dev/null || echo YNH_NULL)"
|
||||||
file_hash[$short_setting]="true"
|
file_hash[$short_setting]="true"
|
||||||
|
|
||||||
# Get multiline text from settings or from a full file
|
# Get multiline text from settings or from a full file
|
||||||
|
@ -32,7 +32,7 @@ _ynh_app_config_get_one() {
|
||||||
elif [[ "$bind" == *":"* ]]; then
|
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"
|
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
|
else
|
||||||
old[$short_setting]="$(cat "$bind" 2> /dev/null || echo YNH_NULL)"
|
old[$short_setting]="$(cat $(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get value from a kind of key/value file
|
# 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_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
||||||
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
||||||
fi
|
fi
|
||||||
local bind_file="$(echo "$bind" | cut -d: -f2)"
|
local bind_file="$(echo "$bind" | cut -d: -f2 | 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}")"
|
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
@ -73,11 +73,11 @@ _ynh_app_config_apply_one() {
|
||||||
if [[ "$bind" == "settings" ]]; then
|
if [[ "$bind" == "settings" ]]; then
|
||||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||||
fi
|
fi
|
||||||
local bind_file="$bind"
|
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
if [[ "${!short_setting}" == "" ]]; then
|
if [[ "${!short_setting}" == "" ]]; then
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
ynh_secure_remove --file="$bind_file"
|
ynh_secure_remove --file="$bind_file"
|
||||||
ynh_delete_file_checksum --file="$bind_file"
|
ynh_delete_file_checksum --file="$bind_file" --update_only
|
||||||
ynh_print_info --message="File '$bind_file' removed"
|
ynh_print_info --message="File '$bind_file' removed"
|
||||||
else
|
else
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
@ -98,7 +98,7 @@ _ynh_app_config_apply_one() {
|
||||||
if [[ "$bind" == *":"* ]]; then
|
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"
|
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
|
fi
|
||||||
local bind_file="$bind"
|
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
echo "${!short_setting}" >"$bind_file"
|
echo "${!short_setting}" >"$bind_file"
|
||||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||||
|
@ -108,12 +108,12 @@ _ynh_app_config_apply_one() {
|
||||||
else
|
else
|
||||||
local bind_after=""
|
local bind_after=""
|
||||||
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||||
|
bind_key_=${bind_key_:-$short_setting}
|
||||||
if [[ "$bind_key_" == *">"* ]]; then
|
if [[ "$bind_key_" == *">"* ]]; then
|
||||||
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
||||||
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
||||||
fi
|
fi
|
||||||
bind_key_=${bind_key_:-$short_setting}
|
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
local bind_file="$(echo "$bind" | cut -d: -f2)"
|
|
||||||
|
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
ynh_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}"
|
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
|
||||||
|
@ -126,17 +126,41 @@ _ynh_app_config_apply_one() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_ynh_app_config_get() {
|
_ynh_app_config_get() {
|
||||||
for line in $YNH_APP_CONFIG_PANEL_OPTIONS_TYPES_AND_BINDS; do
|
# 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
|
||||||
|
for section_name, section in panel.items():
|
||||||
|
if not isinstance(section, dict): continue
|
||||||
|
for name, param in section.items():
|
||||||
|
if not isinstance(param, dict):
|
||||||
|
continue
|
||||||
|
print(';'.join([
|
||||||
|
name,
|
||||||
|
param.get('type', 'string'),
|
||||||
|
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
|
||||||
|
]))
|
||||||
|
EOL
|
||||||
|
)
|
||||||
|
for line in $lines; do
|
||||||
# Split line into short_setting, type and bind
|
# 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"
|
binds[${short_setting}]="$bind"
|
||||||
types[${short_setting}]="$type"
|
types[${short_setting}]="$type"
|
||||||
file_hash[${short_setting}]=""
|
file_hash[${short_setting}]=""
|
||||||
formats[${short_setting}]=""
|
formats[${short_setting}]=""
|
||||||
ynh_app_config_get_one $short_setting $type $bind
|
ynh_app_config_get_one $short_setting $type $bind
|
||||||
done
|
done
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ynh_app_config_apply() {
|
_ynh_app_config_apply() {
|
||||||
|
@ -152,7 +176,8 @@ _ynh_app_config_show() {
|
||||||
ynh_return "${short_setting}:"
|
ynh_return "${short_setting}:"
|
||||||
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
||||||
else
|
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
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -260,18 +285,6 @@ ynh_app_config_apply() {
|
||||||
_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() {
|
ynh_app_config_run() {
|
||||||
declare -Ag old=()
|
declare -Ag old=()
|
||||||
declare -Ag changed=()
|
declare -Ag changed=()
|
||||||
|
@ -296,8 +309,5 @@ ynh_app_config_run() {
|
||||||
ynh_app_config_apply
|
ynh_app_config_apply
|
||||||
ynh_script_progression --message="Configuration of $app completed" --last
|
ynh_script_progression --message="Configuration of $app completed" --last
|
||||||
;;
|
;;
|
||||||
*)
|
|
||||||
ynh_app_action_run $1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
}
|
}
|
|
@ -8,8 +8,11 @@
|
||||||
# | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
|
# | 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
|
# | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
|
||||||
#
|
#
|
||||||
# usage 2: ynh_add_fail2ban_config --use_template
|
# -----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# usage 2: ynh_add_fail2ban_config --use_template [--others_var="list of others variables to replace"]
|
||||||
# | arg: -t, --use_template - Use this helper in template mode
|
# | arg: -t, --use_template - Use this helper in template mode
|
||||||
|
# | arg: -v, --others_var= - List of others variables to replace separeted by a space for example : 'var_1 var_2 ...'
|
||||||
#
|
#
|
||||||
# This will use a template in `../conf/f2b_jail.conf` and `../conf/f2b_filter.conf`
|
# This will use a template in `../conf/f2b_jail.conf` and `../conf/f2b_filter.conf`
|
||||||
# See the documentation of `ynh_add_config` for a description of the template
|
# See the documentation of `ynh_add_config` for a description of the template
|
||||||
|
@ -40,7 +43,9 @@
|
||||||
# ignoreregex =
|
# 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
|
# 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
|
# matched by a group named "`host`". The tag "`<HOST>`" can be used for standard
|
||||||
|
@ -49,6 +54,8 @@
|
||||||
# You can find some more explainations about how to make a regex here :
|
# You can find some more explainations about how to make a regex here :
|
||||||
# https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters
|
# 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:
|
# 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
|
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
|
||||||
|
@ -58,19 +65,23 @@
|
||||||
ynh_add_fail2ban_config() {
|
ynh_add_fail2ban_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=lrmptv
|
local legacy_args=lrmptv
|
||||||
local -A args_array=([l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template)
|
local -A args_array=([l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
||||||
local logpath
|
local logpath
|
||||||
local failregex
|
local failregex
|
||||||
local max_retry
|
local max_retry
|
||||||
local ports
|
local ports
|
||||||
|
local others_var
|
||||||
local use_template
|
local use_template
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
max_retry=${max_retry:-3}
|
max_retry=${max_retry:-3}
|
||||||
ports=${ports:-http,https}
|
ports=${ports:-http,https}
|
||||||
|
others_var="${others_var:-}"
|
||||||
use_template="${use_template:-0}"
|
use_template="${use_template:-0}"
|
||||||
|
|
||||||
if [ "$use_template" -ne 1 ]; then
|
[[ -z "$others_var" ]] || ynh_print_warn --message="Packagers: using --others_var is unecessary since YunoHost 4.2"
|
||||||
|
|
||||||
|
if [ $use_template -ne 1 ]; then
|
||||||
# Usage 1, no template. Build a config file from scratch.
|
# 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 "$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."
|
test -n "$failregex" || ynh_die --message="ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
|
||||||
|
@ -82,7 +93,7 @@ port = __PORTS__
|
||||||
filter = __APP__
|
filter = __APP__
|
||||||
logpath = __LOGPATH__
|
logpath = __LOGPATH__
|
||||||
maxretry = __MAX_RETRY__
|
maxretry = __MAX_RETRY__
|
||||||
" > "$YNH_APP_BASEDIR/conf/f2b_jail.conf"
|
" >$YNH_APP_BASEDIR/conf/f2b_jail.conf
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
[INCLUDES]
|
[INCLUDES]
|
||||||
|
@ -90,28 +101,11 @@ before = common.conf
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = __FAILREGEX__
|
failregex = __FAILREGEX__
|
||||||
ignoreregex =
|
ignoreregex =
|
||||||
" > "$YNH_APP_BASEDIR/conf/f2b_filter.conf"
|
" >$YNH_APP_BASEDIR/conf/f2b_filter.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_add_config --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/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_add_config --template="$YNH_APP_BASEDIR/conf/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_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
||||||
|
|
|
@ -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
|
# 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)
|
# (e.g. for [u]=user, --user will be -u)
|
||||||
# Replace long option with = (match the beginning of the argument)
|
# 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} /")"
|
arguments[arg]="$(echo "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]}/-${option_flag} /")"
|
||||||
# And long option without = (match the whole line)
|
# And long option without = (match the whole line)
|
||||||
arguments[arg]="$(printf '%s\n' "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]%=}$/-${option_flag} /")"
|
arguments[arg]="$(echo "${arguments[arg]}" | sed "s/^--${args_array[$option_flag]%=}$/-${option_flag} /")"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
# Get the total or free amount of RAM+swap on the system
|
# Get the total or free amount of RAM+swap on the system
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_get_ram [--free|--total] [--ignore_swap|--only_swap]
|
# usage: ynh_get_ram [--free|--total] [--ignore_swap|--only_swap]
|
||||||
# | arg: -f, --free - Count free RAM+swap
|
# | arg: -f, --free - Count free RAM+swap
|
||||||
# | arg: -t, --total - Count total RAM+swap
|
# | arg: -t, --total - Count total RAM+swap
|
||||||
|
@ -32,8 +30,8 @@ ynh_get_ram() {
|
||||||
ram=0
|
ram=0
|
||||||
# Use the total amount of ram
|
# Use the total amount of ram
|
||||||
elif [ $free -eq 1 ]; then
|
elif [ $free -eq 1 ]; then
|
||||||
local free_ram=$(LC_ALL=C vmstat --stats --unit M | grep "free memory" | awk '{print $1}')
|
local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}')
|
||||||
local free_swap=$(LC_ALL=C vmstat --stats --unit M | grep "free swap" | awk '{print $1}')
|
local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}')
|
||||||
local free_ram_swap=$((free_ram + free_swap))
|
local free_ram_swap=$((free_ram + free_swap))
|
||||||
|
|
||||||
# Use the total amount of free ram
|
# Use the total amount of free ram
|
||||||
|
@ -46,8 +44,8 @@ ynh_get_ram() {
|
||||||
ram=$free_swap
|
ram=$free_swap
|
||||||
fi
|
fi
|
||||||
elif [ $total -eq 1 ]; then
|
elif [ $total -eq 1 ]; then
|
||||||
local total_ram=$(LC_ALL=C vmstat --stats --unit M | grep "total memory" | awk '{print $1}')
|
local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}')
|
||||||
local total_swap=$(LC_ALL=C vmstat --stats --unit M | grep "total swap" | awk '{print $1}')
|
local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}')
|
||||||
local total_ram_swap=$((total_ram + total_swap))
|
local total_ram_swap=$((total_ram + total_swap))
|
||||||
|
|
||||||
local ram=$total_ram_swap
|
local ram=$total_ram_swap
|
||||||
|
@ -65,8 +63,6 @@ ynh_get_ram() {
|
||||||
|
|
||||||
# Return 0 or 1 depending if the system has a given amount of RAM+swap free or total
|
# 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]
|
# usage: ynh_require_ram --required=RAM [--free|--total] [--ignore_swap|--only_swap]
|
||||||
# | arg: -r, --required= - The amount to require, in MB
|
# | arg: -r, --required= - The amount to require, in MB
|
||||||
# | arg: -f, --free - Count free RAM+swap
|
# | arg: -f, --free - Count free RAM+swap
|
|
@ -93,11 +93,12 @@ ynh_exec_err() {
|
||||||
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
# (because in the past eval was used) ...
|
# (because in the past eval was used) ...
|
||||||
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
ynh_print_err --message="$(eval $@)"
|
then
|
||||||
|
ynh_print_err "$(eval $@)"
|
||||||
else
|
else
|
||||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
ynh_print_err --message="$("$@")"
|
ynh_print_err "$("$@")"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,11 +114,12 @@ ynh_exec_warn() {
|
||||||
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
# (because in the past eval was used) ...
|
# (because in the past eval was used) ...
|
||||||
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
ynh_print_warn --message="$(eval $@)"
|
then
|
||||||
|
ynh_print_warn "$(eval $@)"
|
||||||
else
|
else
|
||||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
ynh_print_warn --message="$("$@")"
|
ynh_print_warn "$("$@")"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +135,8 @@ ynh_exec_warn_less() {
|
||||||
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
# (because in the past eval was used) ...
|
# (because in the past eval was used) ...
|
||||||
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ 2>&1
|
eval $@ 2>&1
|
||||||
else
|
else
|
||||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
@ -153,7 +156,8 @@ ynh_exec_quiet() {
|
||||||
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
# (because in the past eval was used) ...
|
# (because in the past eval was used) ...
|
||||||
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ > /dev/null
|
eval $@ > /dev/null
|
||||||
else
|
else
|
||||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
@ -173,7 +177,8 @@ ynh_exec_fully_quiet() {
|
||||||
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
# (because in the past eval was used) ...
|
# (because in the past eval was used) ...
|
||||||
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ > /dev/null 2>&1
|
eval $@ > /dev/null 2>&1
|
||||||
else
|
else
|
||||||
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
@ -181,26 +186,6 @@ ynh_exec_fully_quiet() {
|
||||||
fi
|
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.
|
# Remove any logs for all the following commands.
|
||||||
#
|
#
|
||||||
# usage: ynh_print_OFF
|
# usage: ynh_print_OFF
|
||||||
|
@ -263,14 +248,7 @@ ynh_script_progression() {
|
||||||
# Re-disable xtrace, ynh_handle_getopts_args set it back
|
# Re-disable xtrace, ynh_handle_getopts_args set it back
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
weight=${weight:-1}
|
weight=${weight:-1}
|
||||||
|
|
||||||
# Always activate time when running inside CI tests
|
|
||||||
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
|
|
||||||
time=${time:-1}
|
|
||||||
else
|
|
||||||
time=${time:-0}
|
time=${time:-0}
|
||||||
fi
|
|
||||||
|
|
||||||
last=${last:-0}
|
last=${last:-0}
|
||||||
|
|
||||||
# Get execution time since the last $base_time
|
# Get execution time since the last $base_time
|
||||||
|
@ -323,8 +301,8 @@ ynh_script_progression() {
|
||||||
local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}"
|
local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}"
|
||||||
|
|
||||||
local print_exec_time=""
|
local print_exec_time=""
|
||||||
if [ $time -eq 1 ] && [ "$exec_time" -gt 10 ]; then
|
if [ $time -eq 1 ]; then
|
||||||
print_exec_time=" [$(bc <<< "scale=1; $exec_time / 60") minutes]"
|
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
|
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
|
104
data/helpers.d/logrotate
Normal file
104
data/helpers.d/logrotate
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Use logrotate to manage the logfile
|
||||||
|
#
|
||||||
|
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
|
||||||
|
# | arg: -l, --logfile= - absolute path of logfile
|
||||||
|
# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config.
|
||||||
|
# | 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.
|
||||||
|
#
|
||||||
|
# It's possible to use this helper multiple times, each config will be added to
|
||||||
|
# the same logrotate config file. Unless you use the option `--non-append`
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
|
# Requires YunoHost version 3.2.0 or higher for the argument `--specific_user`
|
||||||
|
ynh_use_logrotate() {
|
||||||
|
# Declare an array to define the options of this helper.
|
||||||
|
local legacy_args=lnuya
|
||||||
|
local -A args_array=([l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append)
|
||||||
|
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
|
||||||
|
local logfile
|
||||||
|
local nonappend
|
||||||
|
local specific_user
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
logfile="${logfile:-}"
|
||||||
|
nonappend="${nonappend:-0}"
|
||||||
|
specific_user="${specific_user:-}"
|
||||||
|
|
||||||
|
# LEGACY CODE - PRE GETOPTS
|
||||||
|
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
|
||||||
|
nonappend=1
|
||||||
|
# Destroy this argument for the next command.
|
||||||
|
shift
|
||||||
|
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
|
||||||
|
nonappend=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
|
||||||
|
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
|
||||||
|
# we just want to manage a single file
|
||||||
|
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then
|
||||||
|
local logfile=$1
|
||||||
|
# Otherwise we assume we want to manage a directory and all its .log file inside
|
||||||
|
else
|
||||||
|
local logfile=$1/*.log
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# LEGACY CODE
|
||||||
|
|
||||||
|
local customtee="tee --append"
|
||||||
|
if [ "$nonappend" -eq 1 ]; then
|
||||||
|
customtee="tee"
|
||||||
|
fi
|
||||||
|
if [ -n "$logfile" ]; then
|
||||||
|
if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
|
||||||
|
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
|
||||||
|
fi
|
||||||
|
local su_directive=""
|
||||||
|
if [[ -n $specific_user ]]; then
|
||||||
|
su_directive=" # Run logorotate as specific user - group
|
||||||
|
su ${specific_user%/*} ${specific_user#*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >./${app}-logrotate <<EOF # Build a config file for logrotate
|
||||||
|
$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 move the log.
|
||||||
|
copytruncate
|
||||||
|
# Do not do an error if the log is missing
|
||||||
|
missingok
|
||||||
|
# Not rotate if the log is empty
|
||||||
|
notifempty
|
||||||
|
# Keep old logs in the same dir
|
||||||
|
noolddir
|
||||||
|
$su_directive
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist
|
||||||
|
cat ${app}-logrotate | $customtee /etc/logrotate.d/$app >/dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
|
@ -44,11 +44,11 @@ ynh_multimedia_build_main_dir() {
|
||||||
|
|
||||||
## Application des droits étendus sur le dossier multimedia.
|
## 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:
|
# 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" || true
|
setfacl -RnL -m g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY"
|
||||||
# Application de la même règle que précédemment, mais par défaut pour les nouveaux fichiers.
|
# 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" || true
|
setfacl -RnL -m d:g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY"
|
||||||
# Réglage du masque par défaut. Qui garantie (en principe...) un droit maximal à rwx. Donc pas de restriction de droits par l'acl.
|
# 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
|
setfacl -RL -m m::rwx "$MEDIA_DIRECTORY"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add a directory in yunohost.multimedia
|
# Add a directory in yunohost.multimedia
|
|
@ -133,7 +133,7 @@ ynh_mysql_dump_db() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
mysqldump --single-transaction --skip-dump-date --routines "$database"
|
mysqldump --single-transaction --skip-dump-date "$database"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a user
|
# Create a user
|
||||||
|
@ -152,8 +152,6 @@ ynh_mysql_create_user() {
|
||||||
|
|
||||||
# Check if a mysql user exists
|
# Check if a mysql user exists
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_mysql_user_exists --user=user
|
# usage: ynh_mysql_user_exists --user=user
|
||||||
# | arg: -u, --user= - the user for which to check existence
|
# | arg: -u, --user= - the user for which to check existence
|
||||||
# | ret: 0 if the user exists, 1 otherwise.
|
# | ret: 0 if the user exists, 1 otherwise.
|
||||||
|
@ -174,19 +172,6 @@ ynh_mysql_user_exists() {
|
||||||
fi
|
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
|
# Drop a user
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
|
@ -201,8 +186,6 @@ ynh_mysql_drop_user() {
|
||||||
|
|
||||||
# Create a database, an user and its password. Then store the password in the app's config
|
# 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]
|
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||||
# | arg: -u, --db_user= - Owner of the database
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
# | arg: -n, --db_name= - Name of the database
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
@ -233,8 +216,6 @@ ynh_mysql_setup_db() {
|
||||||
|
|
||||||
# Remove a database if it exists, and the associated user
|
# Remove a database if it exists, and the associated user
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
|
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
|
||||||
# | arg: -u, --db_user= - Owner of the database
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
# | arg: -n, --db_name= - Name of the database
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
@ -249,7 +230,7 @@ ynh_mysql_remove_db() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_mysql_database_exists "$db_name"; then
|
if mysqlshow | grep -q "^| $db_name "; then
|
||||||
ynh_mysql_drop_db $db_name
|
ynh_mysql_drop_db $db_name
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="Database $db_name not found"
|
ynh_print_warn --message="Database $db_name not found"
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
# Find a free port and return it
|
# Find a free port and return it
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_find_port --port=begin_port
|
# usage: ynh_find_port --port=begin_port
|
||||||
# | arg: -p, --port= - port to start to search
|
# | arg: -p, --port= - port to start to search
|
||||||
# | ret: the port number
|
# | ret: the port number
|
||||||
|
@ -28,8 +26,6 @@ ynh_find_port() {
|
||||||
|
|
||||||
# Test if a port is available
|
# Test if a port is available
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_find_port --port=XYZ
|
# usage: ynh_find_port --port=XYZ
|
||||||
# | arg: -p, --port= - port to check
|
# | arg: -p, --port= - port to check
|
||||||
# | ret: 0 if the port is available, 1 if it is already used by another process.
|
# | ret: 0 if the port is available, 1 if it is already used by another process.
|
|
@ -20,15 +20,13 @@ ynh_add_nginx_config() {
|
||||||
|
|
||||||
local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
|
|
||||||
ynh_add_config --template="nginx.conf" --destination="$finalnginxconf"
|
|
||||||
|
|
||||||
if [ "${path_url:-}" != "/" ]; then
|
if [ "${path_url:-}" != "/" ]; then
|
||||||
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf"
|
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
||||||
else
|
else
|
||||||
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf"
|
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_store_file_checksum --file="$finalnginxconf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/nginx.conf" --destination="$finalnginxconf"
|
||||||
|
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
@ -42,23 +40,3 @@ ynh_remove_nginx_config() {
|
||||||
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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
|
|
||||||
ynh_backup_if_checksum_is_different --file="$old_nginx_conf_path"
|
|
||||||
ynh_delete_file_checksum --file="$old_nginx_conf_path"
|
|
||||||
ynh_secure_remove --file="$old_nginx_conf_path"
|
|
||||||
|
|
||||||
# Regen the nginx conf
|
|
||||||
ynh_add_nginx_config
|
|
||||||
}
|
|
|
@ -1,10 +1,31 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
n_version=8.0.1
|
||||||
n_install_dir="/opt/node_n"
|
n_install_dir="/opt/node_n"
|
||||||
node_version_path="$n_install_dir/n/versions/node"
|
node_version_path="$n_install_dir/n/versions/node"
|
||||||
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
|
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
|
||||||
export N_PREFIX="$n_install_dir"
|
export N_PREFIX="$n_install_dir"
|
||||||
|
|
||||||
|
# Install Node version management
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_install_n
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
|
ynh_install_n() {
|
||||||
|
# Build an app.src for n
|
||||||
|
echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz
|
||||||
|
SOURCE_SUM=8703ae88fd06ce7f2d0f4018d68bfbab7b26859ed86a86ce4b8f25d2110aee2f" >"$YNH_APP_BASEDIR/conf/n.src"
|
||||||
|
# Download and extract n
|
||||||
|
ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
|
||||||
|
# Install n
|
||||||
|
(
|
||||||
|
cd "$n_install_dir/git"
|
||||||
|
PREFIX=$N_PREFIX make install 2>&1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
# Load the version of node for an app, and set variables.
|
# Load the version of node for an app, and set variables.
|
||||||
#
|
#
|
||||||
# usage: ynh_use_nodejs
|
# usage: ynh_use_nodejs
|
||||||
|
@ -74,8 +95,6 @@ ynh_use_nodejs() {
|
||||||
ynh_node_load_PATH="PATH=$node_PATH"
|
ynh_node_load_PATH="PATH=$node_PATH"
|
||||||
# Same var but in lower case to be compatible with ynh_replace_vars...
|
# Same var but in lower case to be compatible with ynh_replace_vars...
|
||||||
ynh_node_load_path="PATH=$node_PATH"
|
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
|
# Install a specific version of nodejs
|
||||||
|
@ -83,7 +102,7 @@ ynh_use_nodejs() {
|
||||||
# ynh_install_nodejs will install the version of node provided as argument by using n.
|
# ynh_install_nodejs will install the version of node provided as argument by using n.
|
||||||
#
|
#
|
||||||
# usage: ynh_install_nodejs --nodejs_version=nodejs_version
|
# 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).
|
# | 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.
|
||||||
#
|
#
|
||||||
# `n` (Node version management) uses the `PATH` variable to store the path of the version of node it is going to use.
|
# `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
|
# That's how it changes the version
|
||||||
|
@ -113,10 +132,14 @@ ynh_install_nodejs() {
|
||||||
test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n
|
test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n
|
||||||
test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n
|
test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n
|
||||||
|
|
||||||
# Install (or update if YunoHost vendor/ folder updated since last install) n
|
# If n is not previously setup, install it
|
||||||
mkdir -p $n_install_dir/bin/
|
if ! $n_install_dir/bin/n --version >/dev/null 2>&1; then
|
||||||
cp "$YNH_HELPERS_DIR/vendor/n/n" $n_install_dir/bin/n
|
ynh_install_n
|
||||||
# Tweak for n to understand it's installed in $N_PREFIX
|
elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version; then
|
||||||
|
ynh_install_n
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Modify the default N_PREFIX in n script
|
||||||
ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n"
|
ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n"
|
||||||
|
|
||||||
# Restore /usr/local/bin in PATH
|
# Restore /usr/local/bin in PATH
|
||||||
|
@ -144,11 +167,14 @@ ynh_install_nodejs() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Store the ID of this app and the version of node requested for it
|
# Store the ID of this app and the version of node requested for it
|
||||||
echo "$app:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
||||||
|
|
||||||
# Store nodejs_version into the config of this app
|
# Store nodejs_version into the config of this app
|
||||||
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
|
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
|
ynh_use_nodejs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +191,7 @@ ynh_remove_nodejs() {
|
||||||
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
||||||
|
|
||||||
# Remove the line for this app
|
# Remove the line for this app
|
||||||
sed --in-place "/$app:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
||||||
|
|
||||||
# If no other app uses this version of nodejs, remove it.
|
# If no other app uses this version of nodejs, remove it.
|
||||||
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"; then
|
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"; then
|
||||||
|
@ -177,5 +203,62 @@ ynh_remove_nodejs() {
|
||||||
ynh_secure_remove --file="$n_install_dir"
|
ynh_secure_remove --file="$n_install_dir"
|
||||||
ynh_secure_remove --file="/usr/local/n"
|
ynh_secure_remove --file="/usr/local/n"
|
||||||
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
||||||
|
rm --force /etc/cron.daily/node_update
|
||||||
fi
|
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,50 +1,39 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
readonly YNH_DEFAULT_PHP_VERSION=7.4
|
readonly YNH_DEFAULT_PHP_VERSION=7.3
|
||||||
# Declare the actual PHP version to use.
|
# Declare the actual PHP version to use.
|
||||||
# A packager willing to use another version of PHP can override the variable into its _common.sh.
|
# A packager willing to use another version of PHP can override the variable into its _common.sh.
|
||||||
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
|
|
||||||
# Create a dedicated PHP-FPM config
|
# Create a dedicated PHP-FPM config
|
||||||
#
|
#
|
||||||
# usage: ynh_add_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.
|
||||||
#
|
#
|
||||||
# Case 1 (recommended) : your provided a snippet conf/extra_php-fpm.conf
|
# -----------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# The actual PHP configuration will be automatically generated,
|
# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] [--dedicated_service]
|
||||||
# and your extra_php-fpm.conf will be appended (typically contains PHP upload limits)
|
# | arg: -v, --phpversion= - Version of PHP to use.
|
||||||
#
|
# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high).
|
||||||
# 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.
|
# low - Less than 20 MB of RAM by pool.
|
||||||
# medium - Between 20 MB and 40 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.
|
# high - More than 40 MB of RAM by pool.
|
||||||
# N - Or you can specify a quantitative footprint as MB by pool (use watch -n0.5 ps -o user,cmd,%cpu,rss -u APP)
|
# 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
|
||||||
#
|
#
|
||||||
# fpm_usage: Expected usage of the service (low/medium/high).
|
# | arg: -u, --usage= - Expected usage of the service (low/medium/high).
|
||||||
# low - Personal usage, behind the SSO.
|
# low - Personal usage, behind the SSO.
|
||||||
# medium - Low usage, few people or/and publicly accessible.
|
# medium - Low usage, few people or/and publicly accessible.
|
||||||
# high - High usage, frequently visited website.
|
# 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.
|
# 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'
|
# 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
|
# A lower value for the footprint will allow more children for 'pm.max_children'. And so for
|
||||||
|
@ -68,12 +57,11 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_fpm_config() {
|
ynh_add_fpm_config() {
|
||||||
local _globalphpversion=${phpversion-:}
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vufpdg
|
local legacy_args=vtufpd
|
||||||
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service [g]=group=)
|
local -A args_array=([v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
|
||||||
local group
|
|
||||||
local phpversion
|
local phpversion
|
||||||
|
local use_template
|
||||||
local usage
|
local usage
|
||||||
local footprint
|
local footprint
|
||||||
local package
|
local package
|
||||||
|
@ -81,49 +69,29 @@ ynh_add_fpm_config() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
package=${package:-}
|
package=${package:-}
|
||||||
group=${group:-}
|
|
||||||
|
|
||||||
# The default behaviour is to use the template.
|
# The default behaviour is to use the template.
|
||||||
local autogenconf=false
|
use_template="${use_template:-1}"
|
||||||
usage="${usage:-}"
|
usage="${usage:-}"
|
||||||
footprint="${footprint:-}"
|
footprint="${footprint:-}"
|
||||||
if [ -n "$usage" ] || [ -n "$footprint" ] || [[ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]]; then
|
if [ -n "$usage" ] || [ -n "$footprint" ]; then
|
||||||
autogenconf=true
|
use_template=0
|
||||||
|
|
||||||
# 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
|
fi
|
||||||
# Do not use a dedicated service by default
|
# Do not use a dedicated service by default
|
||||||
dedicated_service=${dedicated_service:-0}
|
dedicated_service=${dedicated_service:-0}
|
||||||
|
|
||||||
# Set the default PHP-FPM version by default
|
# Set the default PHP-FPM version by default
|
||||||
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
|
|
||||||
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||||
else
|
|
||||||
phpversion="${phpversion:-$_globalphpversion}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
||||||
|
|
||||||
# If the PHP version changed, remove the old fpm conf
|
# If the PHP version changed, remove the old fpm conf
|
||||||
# (NB: This stuff is also handled by the apt helper, which is usually triggered before this helper)
|
|
||||||
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]; then
|
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]; then
|
||||||
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
||||||
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
||||||
|
|
||||||
if [[ -f "$old_php_finalphpconf" ]]; then
|
if [[ -f "$old_php_finalphpconf" ]]
|
||||||
|
then
|
||||||
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
|
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
|
||||||
ynh_remove_fpm_config
|
ynh_remove_fpm_config
|
||||||
fi
|
fi
|
||||||
|
@ -132,12 +100,10 @@ ynh_add_fpm_config() {
|
||||||
# Legacy args (packager should just list their php dependency as regular apt dependencies...
|
# Legacy args (packager should just list their php dependency as regular apt dependencies...
|
||||||
if [ -n "$package" ]; then
|
if [ -n "$package" ]; then
|
||||||
# Install the additionnal packages from the default repository
|
# 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"
|
ynh_install_app_dependencies "$package"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
ynh_print_warn --message "Argument --dedicated_service of ynh_add_fpm_config is deprecated and to be removed in the future"
|
|
||||||
local fpm_service="${app}-phpfpm"
|
local fpm_service="${app}-phpfpm"
|
||||||
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
|
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
|
||||||
else
|
else
|
||||||
|
@ -168,7 +134,7 @@ ynh_add_fpm_config() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $autogenconf == "false" ]; then
|
if [ $use_template -eq 1 ]; then
|
||||||
# Usage 1, use the template in conf/php-fpm.conf
|
# Usage 1, use the template in conf/php-fpm.conf
|
||||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||||
# Make sure now that the template indeed exists
|
# Make sure now that the template indeed exists
|
||||||
|
@ -176,18 +142,21 @@ ynh_add_fpm_config() {
|
||||||
else
|
else
|
||||||
# Usage 2, generate a PHP-FPM config file with ynh_get_scalable_phpfpm
|
# 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.
|
# Define the values to use for the configuration of PHP.
|
||||||
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
|
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
|
||||||
|
|
||||||
local phpfpm_group=$([[ -n "$group" ]] && echo "$group" || echo "$app")
|
|
||||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||||
echo "
|
echo "
|
||||||
[__APP__]
|
[__APP__]
|
||||||
|
|
||||||
user = __APP__
|
user = __APP__
|
||||||
group = __PHPFPM_GROUP__
|
group = __APP__
|
||||||
|
|
||||||
chdir = __INSTALL_DIR__
|
chdir = __FINALPATH__
|
||||||
|
|
||||||
listen = /var/run/php/php__PHPVERSION__-fpm-__APP__.sock
|
listen = /var/run/php/php__PHPVERSION__-fpm-__APP__.sock
|
||||||
listen.owner = www-data
|
listen.owner = www-data
|
||||||
|
@ -197,19 +166,19 @@ pm = __PHP_PM__
|
||||||
pm.max_children = __PHP_MAX_CHILDREN__
|
pm.max_children = __PHP_MAX_CHILDREN__
|
||||||
pm.max_requests = 500
|
pm.max_requests = 500
|
||||||
request_terminate_timeout = 1d
|
request_terminate_timeout = 1d
|
||||||
" > "$phpfpm_path"
|
" >$phpfpm_path
|
||||||
|
|
||||||
if [ "$php_pm" = "dynamic" ]; then
|
if [ "$php_pm" = "dynamic" ]; then
|
||||||
echo "
|
echo "
|
||||||
pm.start_servers = __PHP_START_SERVERS__
|
pm.start_servers = __PHP_START_SERVERS__
|
||||||
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
|
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
|
||||||
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
|
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
|
||||||
" >> "$phpfpm_path"
|
" >>$phpfpm_path
|
||||||
|
|
||||||
elif [ "$php_pm" = "ondemand" ]; then
|
elif [ "$php_pm" = "ondemand" ]; then
|
||||||
echo "
|
echo "
|
||||||
pm.process_idle_timeout = 10s
|
pm.process_idle_timeout = 10s
|
||||||
" >> "$phpfpm_path"
|
" >>$phpfpm_path
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Concatene the extra config.
|
# Concatene the extra config.
|
||||||
|
@ -223,7 +192,7 @@ pm.process_idle_timeout = 10s
|
||||||
|
|
||||||
if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then
|
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_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"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]; then
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
|
@ -237,7 +206,7 @@ syslog.ident = php-fpm-__APP__
|
||||||
include = __FINALPHPCONF__
|
include = __FINALPHPCONF__
|
||||||
" >$YNH_APP_BASEDIR/conf/php-fpm-$app.conf
|
" >$YNH_APP_BASEDIR/conf/php-fpm-$app.conf
|
||||||
|
|
||||||
ynh_add_config --template="php-fpm-$app.conf" --destination="$globalphpconf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm-$app.conf" --destination="$globalphpconf"
|
||||||
|
|
||||||
# Create a config for a dedicated PHP-FPM service for the app
|
# Create a config for a dedicated PHP-FPM service for the app
|
||||||
echo "[Unit]
|
echo "[Unit]
|
||||||
|
@ -314,7 +283,7 @@ ynh_remove_fpm_config() {
|
||||||
# If the PHP version used is not the default version for YunoHost
|
# 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
|
# 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)
|
# (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
|
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] && [ -n "${YNH_APP_PURGE:-}" ]; then
|
||||||
# Remove app dependencies ... but ideally should happen via an explicit call from packager
|
# Remove app dependencies ... but ideally should happen via an explicit call from packager
|
||||||
ynh_remove_app_dependencies
|
ynh_remove_app_dependencies
|
||||||
fi
|
fi
|
||||||
|
@ -497,3 +466,67 @@ ynh_get_scalable_phpfpm() {
|
||||||
fi
|
fi
|
||||||
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=$final_path] --commands="commands"
|
||||||
|
# | arg: -v, --phpversion - PHP version to use with composer
|
||||||
|
# | arg: -w, --workdir - The directory from where the command will be executed. Default $final_path.
|
||||||
|
# | arg: -c, --commands - Commands to execute.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 4.2 or higher.
|
||||||
|
ynh_composer_exec() {
|
||||||
|
# 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:-$final_path}"
|
||||||
|
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||||
|
|
||||||
|
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=$final_path] [--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 $final_path.
|
||||||
|
# | 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() {
|
||||||
|
# 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 "$@"
|
||||||
|
workdir="${workdir:-$final_path}"
|
||||||
|
phpversion="${phpversion:-$YNH_PHP_VERSION}"
|
||||||
|
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
|
#!/bin/bash
|
||||||
|
|
||||||
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
||||||
PSQL_VERSION=13
|
PSQL_VERSION=11
|
||||||
|
|
||||||
# Open a connection as a user
|
# Open a connection as a user
|
||||||
#
|
#
|
||||||
|
@ -160,8 +160,6 @@ ynh_psql_create_user() {
|
||||||
|
|
||||||
# Check if a psql user exists
|
# Check if a psql user exists
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_user_exists --user=user
|
# usage: ynh_psql_user_exists --user=user
|
||||||
# | arg: -u, --user= - the user for which to check existence
|
# | arg: -u, --user= - the user for which to check existence
|
||||||
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
||||||
|
@ -197,12 +195,7 @@ ynh_psql_database_exists() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# if psql is not there, we cannot check the db
|
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then
|
||||||
# though it could exists.
|
|
||||||
if ! command -v psql; then
|
|
||||||
ynh_print_err -m "PostgreSQL is not installed, impossible to check for db existence."
|
|
||||||
return 1
|
|
||||||
elif ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -223,8 +216,6 @@ ynh_psql_drop_user() {
|
||||||
|
|
||||||
# Create a database, an user and its password. Then store the password in the app's config
|
# 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]
|
# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||||
# | arg: -u, --db_user= - Owner of the database
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
# | arg: -n, --db_name= - Name of the database
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
@ -260,8 +251,6 @@ ynh_psql_setup_db() {
|
||||||
|
|
||||||
# Remove a database if it exists, and the associated user
|
# Remove a database if it exists, and the associated user
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_remove_db --db_user=user --db_name=name
|
# usage: ynh_psql_remove_db --db_user=user --db_name=name
|
||||||
# | arg: -u, --db_user= - Owner of the database
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
# | arg: -n, --db_name= - Name of the database
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
@ -292,8 +281,6 @@ ynh_psql_remove_db() {
|
||||||
|
|
||||||
# Create a master password and set up global settings
|
# Create a master password and set up global settings
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_test_if_first_run
|
# usage: ynh_psql_test_if_first_run
|
||||||
#
|
#
|
||||||
# It also make sure that postgresql is installed and running
|
# It also make sure that postgresql is installed and running
|
||||||
|
@ -305,5 +292,34 @@ ynh_psql_test_if_first_run() {
|
||||||
# Make sure postgresql is indeed installed
|
# Make sure postgresql is indeed installed
|
||||||
dpkg --list | grep -q "ii postgresql-$PSQL_VERSION" || ynh_die --message="postgresql-$PSQL_VERSION is not installed !?"
|
dpkg --list | grep -q "ii postgresql-$PSQL_VERSION" || ynh_die --message="postgresql-$PSQL_VERSION is not installed !?"
|
||||||
|
|
||||||
yunohost tools regen-conf postgresql
|
# Check for some weird issue where postgresql could be installed but etc folder would not exist ...
|
||||||
|
[ -e "/etc/postgresql/$PSQL_VERSION" ] || ynh_die --message="It looks like postgresql was not properly configured ? /etc/postgresql/$PSQL_VERSION is missing ... Could be due to a locale issue, c.f.https://serverfault.com/questions/426989/postgresql-etc-postgresql-doesnt-exist"
|
||||||
|
|
||||||
|
# Make sure postgresql is started and enabled
|
||||||
|
# (N.B. : to check the active state, we check the cluster state because
|
||||||
|
# postgresql could be flagged as active even though the cluster is in
|
||||||
|
# failed state because of how the service is configured..)
|
||||||
|
systemctl is-active postgresql@$PSQL_VERSION-main -q || ynh_systemd_action --service_name=postgresql --action=restart
|
||||||
|
systemctl is-enabled postgresql -q || systemctl enable postgresql --quiet
|
||||||
|
|
||||||
|
# If this is the very first time, we define the root password
|
||||||
|
# and configure a few things
|
||||||
|
if [ ! -f "$PSQL_ROOT_PWD_FILE" ]; then
|
||||||
|
local pg_hba=/etc/postgresql/$PSQL_VERSION/main/pg_hba.conf
|
||||||
|
|
||||||
|
local psql_root_password="$(ynh_string_random)"
|
||||||
|
echo "$psql_root_password" >$PSQL_ROOT_PWD_FILE
|
||||||
|
sudo --login --user=postgres psql -c"ALTER user postgres WITH PASSWORD '$psql_root_password'" postgres
|
||||||
|
|
||||||
|
# force all user to connect to local databases using hashed passwords
|
||||||
|
# https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
|
||||||
|
# Note: we can't use peer since YunoHost create users with nologin
|
||||||
|
# See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
|
||||||
|
ynh_replace_string --match_string="local\(\s*\)all\(\s*\)all\(\s*\)peer" --replace_string="local\1all\2all\3md5" --target_file="$pg_hba"
|
||||||
|
|
||||||
|
# Integrate postgresql service in yunohost
|
||||||
|
yunohost service add postgresql --log "/var/log/postgresql/"
|
||||||
|
|
||||||
|
ynh_systemd_action --service_name=postgresql --action=reload
|
||||||
|
fi
|
||||||
}
|
}
|
|
@ -52,42 +52,6 @@ ynh_app_setting_set() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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
|
|
||||||
}
|
|
||||||
|
|
||||||
# Delete an application setting
|
# Delete an application setting
|
||||||
#
|
#
|
||||||
# usage: ynh_app_setting_delete --app=app --key=key
|
# usage: ynh_app_setting_delete --app=app --key=key
|
||||||
|
@ -149,8 +113,6 @@ EOF
|
||||||
|
|
||||||
# Check availability of a web path
|
# Check availability of a web path
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_webpath_available --domain=domain --path_url=path
|
# usage: ynh_webpath_available --domain=domain --path_url=path
|
||||||
# | arg: -d, --domain= - the domain/host of the url
|
# | arg: -d, --domain= - the domain/host of the url
|
||||||
# | arg: -p, --path_url= - the web path to check the availability of
|
# | arg: -p, --path_url= - the web path to check the availability of
|
||||||
|
@ -172,8 +134,6 @@ ynh_webpath_available() {
|
||||||
|
|
||||||
# Register/book a web path for an app
|
# Register/book a web path for an app
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
|
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
|
||||||
# | arg: -a, --app= - the app for which the domain should be registered
|
# | arg: -a, --app= - the app for which the domain should be registered
|
||||||
# | arg: -d, --domain= - the domain/host of the web path
|
# | arg: -d, --domain= - the domain/host of the web path
|
|
@ -4,7 +4,6 @@
|
||||||
#
|
#
|
||||||
# usage: ynh_string_random [--length=string_length]
|
# usage: ynh_string_random [--length=string_length]
|
||||||
# | arg: -l, --length= - the string length to generate (default: 24)
|
# | arg: -l, --length= - the string length to generate (default: 24)
|
||||||
# | arg: -f, --filter= - the kind of characters accepted in the output (default: 'A-Za-z0-9')
|
|
||||||
# | ret: the generated string
|
# | ret: the generated string
|
||||||
#
|
#
|
||||||
# example: pwd=$(ynh_string_random --length=8)
|
# example: pwd=$(ynh_string_random --length=8)
|
||||||
|
@ -12,17 +11,15 @@
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_string_random() {
|
ynh_string_random() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=lf
|
local legacy_args=l
|
||||||
local -A args_array=([l]=length= [f]=filter=)
|
local -A args_array=([l]=length=)
|
||||||
local length
|
local length
|
||||||
local filter
|
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
length=${length:-24}
|
length=${length:-24}
|
||||||
filter=${filter:-'A-Za-z0-9'}
|
|
||||||
|
|
||||||
dd if=/dev/urandom bs=1 count=1000 2>/dev/null \
|
dd if=/dev/urandom bs=1 count=1000 2>/dev/null \
|
||||||
| tr --complement --delete "$filter" \
|
| tr --complement --delete 'A-Za-z0-9' \
|
||||||
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
|
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +45,7 @@ ynh_replace_string() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
|
|
||||||
local delimit=$'\001'
|
local delimit=@
|
||||||
# Escape the delimiter if it's in the string.
|
# Escape the delimiter if it's in the string.
|
||||||
match_string=${match_string//${delimit}/"\\${delimit}"}
|
match_string=${match_string//${delimit}/"\\${delimit}"}
|
||||||
replace_string=${replace_string//${delimit}/"\\${delimit}"}
|
replace_string=${replace_string//${delimit}/"\\${delimit}"}
|
||||||
|
@ -91,8 +88,6 @@ ynh_replace_special_string() {
|
||||||
|
|
||||||
# Sanitize a string intended to be the name of a database
|
# Sanitize a string intended to be the name of a database
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_sanitize_dbid --db_name=name
|
# usage: ynh_sanitize_dbid --db_name=name
|
||||||
# | arg: -n, --db_name= - name to correct/sanitize
|
# | arg: -n, --db_name= - name to correct/sanitize
|
||||||
# | ret: the corrected name
|
# | ret: the corrected name
|
|
@ -15,15 +15,19 @@
|
||||||
ynh_add_systemd_config() {
|
ynh_add_systemd_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=stv
|
local legacy_args=stv
|
||||||
local -A args_array=([s]=service= [t]=template=)
|
local -A args_array=([s]=service= [t]=template= [v]=others_var=)
|
||||||
local service
|
local service
|
||||||
local template
|
local template
|
||||||
|
local others_var
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
service="${service:-$app}"
|
service="${service:-$app}"
|
||||||
template="${template:-systemd.service}"
|
template="${template:-systemd.service}"
|
||||||
|
others_var="${others_var:-}"
|
||||||
|
|
||||||
ynh_add_config --template="$template" --destination="/etc/systemd/system/$service.service"
|
[[ -z "$others_var" ]] || ynh_print_warn --message="Packagers: using --others_var is unecessary since YunoHost 4.2"
|
||||||
|
|
||||||
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/$template" --destination="/etc/systemd/system/$service.service"
|
||||||
|
|
||||||
systemctl enable $service --quiet
|
systemctl enable $service --quiet
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
@ -61,7 +65,7 @@ ynh_remove_systemd_config() {
|
||||||
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot. If not defined it don't wait until the service is completely started.
|
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot. If not defined it don't wait until the service is completely started.
|
||||||
# | arg: -p, --log_path= - Log file - Path to the log file. Default : `/var/log/$app/$app.log`
|
# | arg: -p, --log_path= - Log file - Path to the log file. Default : `/var/log/$app/$app.log`
|
||||||
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
|
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
|
||||||
# | arg: -e, --length= - Length of the error log displayed for debugging : Default : 20
|
# | arg: -e, --length= - Length of the error log : Default : 20
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_systemd_action() {
|
ynh_systemd_action() {
|
||||||
|
@ -110,8 +114,6 @@ ynh_systemd_action() {
|
||||||
action="reload-or-restart"
|
action="reload-or-restart"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local time_start="$(date --utc --rfc-3339=seconds | cut -d+ -f1) UTC"
|
|
||||||
|
|
||||||
# If the service fails to perform the action
|
# If the service fails to perform the action
|
||||||
if ! systemctl $action $service_name; then
|
if ! systemctl $action $service_name; then
|
||||||
# Show syslog for this service
|
# Show syslog for this service
|
||||||
|
@ -128,31 +130,15 @@ ynh_systemd_action() {
|
||||||
if [[ -n "${line_match:-}" ]]; then
|
if [[ -n "${line_match:-}" ]]; then
|
||||||
set +x
|
set +x
|
||||||
local i=0
|
local i=0
|
||||||
local starttime=$(date +%s)
|
|
||||||
for i in $(seq 1 $timeout); do
|
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
|
# 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
|
|
||||||
# For systemd services, we in fact dont rely on the templog, which for some reason is not reliable, but instead re-read journalctl every iteration, starting at the timestamp where we triggered the action
|
|
||||||
if journalctl --unit=$service_name --since="$time_start" --quiet --no-pager --no-hostname | grep --extended-regexp --quiet "$line_match"; then
|
|
||||||
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if grep --extended-regexp --quiet "$line_match" "$templog"; then
|
if grep --extended-regexp --quiet "$line_match" "$templog"; then
|
||||||
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
if [ $i -eq 30 ]; then
|
if [ $i -eq 30 ]; then
|
||||||
echo "(this may take some time)" >&2
|
echo "(this may take some time)" >&2
|
||||||
fi
|
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
|
sleep 1
|
||||||
done
|
done
|
||||||
set -x
|
set -x
|
|
@ -1,8 +1,60 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Check if a user exists on the system
|
# Check if a YunoHost user exists
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
# 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 'toto' '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
|
||||||
#
|
#
|
||||||
# usage: ynh_system_user_exists --username=username
|
# usage: ynh_system_user_exists --username=username
|
||||||
# | arg: -u, --username= - the username to check
|
# | arg: -u, --username= - the username to check
|
||||||
|
@ -22,8 +74,6 @@ ynh_system_user_exists() {
|
||||||
|
|
||||||
# Check if a group exists on the system
|
# Check if a group exists on the system
|
||||||
#
|
#
|
||||||
# [packagingv1]
|
|
||||||
#
|
|
||||||
# usage: ynh_system_group_exists --group=group
|
# usage: ynh_system_group_exists --group=group
|
||||||
# | arg: -g, --group= - the group to check
|
# | arg: -g, --group= - the group to check
|
||||||
# | ret: 0 if the group exists, 1 otherwise.
|
# | ret: 0 if the group exists, 1 otherwise.
|
977
data/helpers.d/utils
Normal file
977
data/helpers.d/utils
Normal file
|
@ -0,0 +1,977 @@
|
||||||
|
#!/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=$?
|
||||||
|
|
||||||
|
rm -rf "/var/cache/yunohost/download/"
|
||||||
|
|
||||||
|
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.
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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"]
|
||||||
|
# | arg: -d, --dest_dir= - Directory where to setup sources
|
||||||
|
# | arg: -s, --source_id= - Name of the source, defaults to `app`
|
||||||
|
# | 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/'
|
||||||
|
#
|
||||||
|
# This helper will read `conf/${source_id}.src`, download and install the sources.
|
||||||
|
#
|
||||||
|
# The src file need to contains:
|
||||||
|
# ```
|
||||||
|
# SOURCE_URL=Address to download the app archive
|
||||||
|
# SOURCE_SUM=Control sum
|
||||||
|
# # (Optional) Program to check the integrity (sha256sum, md5sum...). Default: sha256
|
||||||
|
# SOURCE_SUM_PRG=sha256
|
||||||
|
# # (Optional) Archive format. Default: tar.gz
|
||||||
|
# SOURCE_FORMAT=tar.gz
|
||||||
|
# # (Optional) Put false if sources are directly in the archive root. Default: true
|
||||||
|
# # Instead of true, SOURCE_IN_SUBDIR could be the number of sub directories to remove.
|
||||||
|
# SOURCE_IN_SUBDIR=false
|
||||||
|
# # (Optionnal) Name of the local archive (offline setup support). Default: ${src_id}.${src_format}
|
||||||
|
# SOURCE_FILENAME=example.tar.gz
|
||||||
|
# # (Optional) If it set as false don't extract the source. Default: true
|
||||||
|
# # (Useful to get a debian package or a python wheel.)
|
||||||
|
# SOURCE_EXTRACT=(true|false)
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# The helper will:
|
||||||
|
# - Check if there is a local source archive in `/opt/yunohost-apps-src/$APP_ID/$SOURCE_FILENAME`
|
||||||
|
# - Download `$SOURCE_URL` if there is no local archive
|
||||||
|
# - Check the integrity with `$SOURCE_SUM_PRG -c --status`
|
||||||
|
# - Uncompress the archive to `$dest_dir`.
|
||||||
|
# - If `$SOURCE_IN_SUBDIR` is true, the first level directory of the archive will be removed.
|
||||||
|
# - If `$SOURCE_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=)
|
||||||
|
local dest_dir
|
||||||
|
local source_id
|
||||||
|
local keep
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
source_id="${source_id:-app}"
|
||||||
|
keep="${keep:-}"
|
||||||
|
|
||||||
|
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_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
|
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
|
local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
|
|
||||||
|
# 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_filename" = "" ]; then
|
||||||
|
src_filename="${source_id}.${src_format}"
|
||||||
|
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}/${src_filename}"
|
||||||
|
|
||||||
|
mkdir -p /var/cache/yunohost/download/${YNH_APP_ID}/
|
||||||
|
src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${src_filename}"
|
||||||
|
|
||||||
|
if test -e "$local_src"; then
|
||||||
|
cp $local_src $src_filename
|
||||||
|
else
|
||||||
|
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \
|
||||||
|
|| ynh_die --message="Corrupt source"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Extract source into the app dir
|
||||||
|
mkdir --parents "$dest_dir"
|
||||||
|
|
||||||
|
if [ -n "${final_path:-}" ] && [ "$dest_dir" == "$final_path" ]; then
|
||||||
|
_ynh_apply_default_permissions $dest_dir
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! "$src_extract"; then
|
||||||
|
mv $src_filename $dest_dir
|
||||||
|
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
|
||||||
|
(
|
||||||
|
cd "$dest_dir"
|
||||||
|
for p in $patches_folder/${source_id}-*.patch; do
|
||||||
|
echo $p
|
||||||
|
patch --strip=1 <$p
|
||||||
|
done
|
||||||
|
) || ynh_die --message="Unable to apply patches"
|
||||||
|
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")"
|
||||||
|
cp --archive "$keep_dir/$stuff_to_keep" "$dest_dir/$stuff_to_keep"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
rm -rf /var/cache/yunohost/files_to_keep_during_setup_source/
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# examples:
|
||||||
|
# ynh_add_config --template=".env" --destination="$final_path/.env"
|
||||||
|
# ynh_add_config --template="../conf/.env" --destination="$final_path/.env"
|
||||||
|
# ynh_add_config --template="/etc/nginx/sites-available/default" --destination="etc/nginx/sites-available/mydomain.conf"
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
# __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
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# 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=tdv
|
||||||
|
local -A args_array=([t]=template= [d]=destination=)
|
||||||
|
local template
|
||||||
|
local destination
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
local template_path
|
||||||
|
|
||||||
|
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
|
||||||
|
chown root:root $destination
|
||||||
|
chmod 640 $destination
|
||||||
|
|
||||||
|
cp -f "$template_path" "$destination"
|
||||||
|
|
||||||
|
_ynh_apply_default_permissions $destination
|
||||||
|
|
||||||
|
ynh_replace_vars --file="$destination"
|
||||||
|
|
||||||
|
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
|
||||||
|
# __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
|
||||||
|
if test -n "${final_path:-}"; then
|
||||||
|
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$file"
|
||||||
|
fi
|
||||||
|
if 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"))
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# 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 -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
|
||||||
|
#
|
||||||
|
# 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 line_number=1
|
||||||
|
if [[ -n "$after" ]]; then
|
||||||
|
line_number=$(grep -n $after $file | cut -d: -f1)
|
||||||
|
if [[ -z "$line_number" ]]; then
|
||||||
|
set -o xtrace # set -x
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
local range="${line_number},\$ "
|
||||||
|
|
||||||
|
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
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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')"
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fetch the Debian release codename
|
||||||
|
#
|
||||||
|
# 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a directory under /tmp
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# Deprecated helper
|
||||||
|
#
|
||||||
|
# usage: ynh_mkdir_tmp
|
||||||
|
# | ret: the created directory path
|
||||||
|
ynh_mkdir_tmp() {
|
||||||
|
ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated."
|
||||||
|
ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \
|
||||||
|
properly with chmod/chown."
|
||||||
|
local TMP_DIR=$(mktemp --directory)
|
||||||
|
|
||||||
|
# Give rights to other users could be a security risk.
|
||||||
|
# But for retrocompatibility we need it. (This helpers is deprecated)
|
||||||
|
chmod 755 $TMP_DIR
|
||||||
|
echo $TMP_DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
_acceptable_path_to_delete() {
|
||||||
|
local file=$1
|
||||||
|
|
||||||
|
local forbidden_paths=$(ls -d / /* /{var,home,usr}/* /etc/{default,sudoers.d,yunohost,cron*})
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract a key from a plain command output
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# (Deprecated, use --output-as json and jq instead)
|
||||||
|
ynh_get_plain_key() {
|
||||||
|
local prefix="#"
|
||||||
|
local found=0
|
||||||
|
# We call this key_ so that it's not caught as
|
||||||
|
# an info to be redacted by the core
|
||||||
|
local key_=$1
|
||||||
|
shift
|
||||||
|
while read line; do
|
||||||
|
if [[ "$found" == "1" ]]; then
|
||||||
|
[[ "$line" =~ ^${prefix}[^#] ]] && return
|
||||||
|
echo $line
|
||||||
|
elif [[ "$line" =~ ^${prefix}${key_}$ ]]; then
|
||||||
|
if [[ -n "${1:-}" ]]; then
|
||||||
|
prefix+="#"
|
||||||
|
key_=$1
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
found=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the value of a key in a ynh manifest file
|
||||||
|
#
|
||||||
|
# usage: ynh_read_manifest --manifest="manifest.json" --key="key"
|
||||||
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
|
# | arg: -k, --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.
|
||||||
|
manifest="$YNH_APP_BASEDIR/manifest.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq ".$manifest_key" "$manifest" --raw-output
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# You can force an upgrade, even if the package is up to date, with the `--force` (or `-F`) argument :
|
||||||
|
# ```
|
||||||
|
# sudo yunohost app upgrade <appname> --force
|
||||||
|
# ```
|
||||||
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
|
ynh_check_app_version_changed() {
|
||||||
|
local return_value=${YNH_APP_UPGRADE_TYPE}
|
||||||
|
|
||||||
|
if [ "$return_value" == "UPGRADE_FULL" ] || [ "$return_value" == "UPGRADE_FORCED" ] || [ "$return_value" == "DOWNGRADE_FORCED" ]; 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
|
||||||
|
|
||||||
|
local ynh_requirement=$(jq -r '.requirements.yunohost' $YNH_APP_BASEDIR/manifest.json | tr -d '>= ')
|
||||||
|
|
||||||
|
if [ -z "$ynh_requirement" ] || [ "$ynh_requirement" == "null" ] || dpkg --compare-versions $ynh_requirement ge 4.2; then
|
||||||
|
chmod o-rwx $target
|
||||||
|
chmod g-w $target
|
||||||
|
chown -R root:root $target
|
||||||
|
if ynh_system_user_exists $app; then
|
||||||
|
chown $app:$app $target
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Crons should be owned by root otherwise they probably don't run
|
||||||
|
if echo "$target" | grep -q '^/etc/cron'
|
||||||
|
then
|
||||||
|
chmod 400 $target
|
||||||
|
chown root:root $target
|
||||||
|
fi
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ source /usr/share/yunohost/helpers
|
||||||
# Backup destination
|
# Backup destination
|
||||||
backup_dir="${1}/data/multimedia"
|
backup_dir="${1}/data/multimedia"
|
||||||
|
|
||||||
if [ ! -e "/home/yunohost.multimedia" ] || [ -e "/home/yunohost.multimedia/.nobackup" ]; then
|
if [ -e "/home/yunohost.multimedia/.nobackup" ]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -13,6 +13,6 @@ backup_dir="${1}/conf/ynh"
|
||||||
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"
|
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"
|
||||||
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"
|
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"
|
||||||
[ ! -d "/etc/yunohost/domains" ] || ynh_backup "/etc/yunohost/domains" "${backup_dir}/domains"
|
[ ! -d "/etc/yunohost/domains" ] || ynh_backup "/etc/yunohost/domains" "${backup_dir}/domains"
|
||||||
[ ! -e "/etc/yunohost/settings.yml" ] || ynh_backup "/etc/yunohost/settings.yml" "${backup_dir}/settings.yml"
|
[ ! -e "/etc/yunohost/settings.json" ] || ynh_backup "/etc/yunohost/settings.json" "${backup_dir}/settings.json"
|
||||||
[ ! -d "/etc/yunohost/dyndns" ] || ynh_backup "/etc/yunohost/dyndns" "${backup_dir}/dyndns"
|
[ ! -d "/etc/yunohost/dyndns" ] || ynh_backup "/etc/yunohost/dyndns" "${backup_dir}/dyndns"
|
||||||
[ ! -d "/etc/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim"
|
[ ! -d "/etc/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim"
|
|
@ -8,7 +8,7 @@ do_init_regen() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/yunohost
|
cd /usr/share/yunohost/templates/yunohost
|
||||||
|
|
||||||
[[ -d /etc/yunohost ]] || mkdir -p /etc/yunohost
|
[[ -d /etc/yunohost ]] || mkdir -p /etc/yunohost
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ do_init_regen() {
|
||||||
# Backup folders
|
# Backup folders
|
||||||
mkdir -p /home/yunohost.backup/archives
|
mkdir -p /home/yunohost.backup/archives
|
||||||
chmod 750 /home/yunohost.backup/archives
|
chmod 750 /home/yunohost.backup/archives
|
||||||
chown root:root /home/yunohost.backup/archives # This is later changed to root:admins once the admins group exists
|
chown root:root /home/yunohost.backup/archives # This is later changed to admin:root once admin user exists
|
||||||
|
|
||||||
# Empty ssowat json persistent conf
|
# Empty ssowat json persistent conf
|
||||||
echo "{}" >'/etc/ssowat/conf.json.persistent'
|
echo "{}" >'/etc/ssowat/conf.json.persistent'
|
||||||
|
@ -56,25 +56,13 @@ do_init_regen() {
|
||||||
chown root:root /var/cache/yunohost
|
chown root:root /var/cache/yunohost
|
||||||
chmod 700 /var/cache/yunohost
|
chmod 700 /var/cache/yunohost
|
||||||
|
|
||||||
cp yunohost-api.service /etc/systemd/system/yunohost-api.service
|
|
||||||
cp yunohost-firewall.service /etc/systemd/system/yunohost-firewall.service
|
|
||||||
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
|
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
|
||||||
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
systemctl enable yunohost-api.service --quiet
|
|
||||||
systemctl start yunohost-api.service
|
|
||||||
|
|
||||||
# Enable yunoprompt (in particular for installs from ISO where we want this to show on first boot instead of asking for a login/password)
|
|
||||||
systemctl enable yunoprompt --quiet
|
|
||||||
|
|
||||||
# Yunohost-firewall is enabled only during postinstall, not init, not 100% sure why
|
|
||||||
|
|
||||||
cp dpkg-origins /etc/dpkg/origins/yunohost
|
cp dpkg-origins /etc/dpkg/origins/yunohost
|
||||||
|
|
||||||
# Change dpkg vendor
|
# Change dpkg vendor
|
||||||
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
||||||
if readlink -f /etc/dpkg/origins/default | grep -q debian; then
|
if readlink -f /etc/dpkg/origins/default | grep -q debian;
|
||||||
|
then
|
||||||
rm -f /etc/dpkg/origins/default
|
rm -f /etc/dpkg/origins/default
|
||||||
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
||||||
fi
|
fi
|
||||||
|
@ -83,7 +71,11 @@ do_init_regen() {
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/yunohost
|
cd /usr/share/yunohost/templates/yunohost
|
||||||
|
|
||||||
|
# Legacy code that can be removed once on bullseye
|
||||||
|
touch /etc/yunohost/services.yml
|
||||||
|
yunohost tools shell -c "from yunohost.service import _get_services, _save_services; _save_services(_get_services())"
|
||||||
|
|
||||||
mkdir -p $pending_dir/etc/systemd/system
|
mkdir -p $pending_dir/etc/systemd/system
|
||||||
mkdir -p $pending_dir/etc/cron.d/
|
mkdir -p $pending_dir/etc/cron.d/
|
||||||
|
@ -100,7 +92,7 @@ EOF
|
||||||
# Cron job that upgrade the app list everyday
|
# Cron job that upgrade the app list everyday
|
||||||
cat >$pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog <<EOF
|
cat >$pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
sleep \$((RANDOM%3600)); yunohost tools update apps > /dev/null
|
(sleep \$((RANDOM%3600)); yunohost tools update --apps > /dev/null) &
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Cron job that renew lets encrypt certificates if there's any that needs renewal
|
# Cron job that renew lets encrypt certificates if there's any that needs renewal
|
||||||
|
@ -112,7 +104,7 @@ EOF
|
||||||
# If we subscribed to a dyndns domain, add the corresponding cron
|
# If we subscribed to a dyndns domain, add the corresponding cron
|
||||||
# - delay between 0 and 60 secs to spread the check over a 1 min window
|
# - delay between 0 and 60 secs to spread the check over a 1 min window
|
||||||
# - do not run the command if some process already has the lock, to avoid queuing hundreds of commands...
|
# - do not run the command if some process already has the lock, to avoid queuing hundreds of commands...
|
||||||
if ls -l /etc/yunohost/dyndns/K*.key 2> /dev/null; then
|
if ls -l /etc/yunohost/dyndns/K*.private 2>/dev/null; then
|
||||||
cat >$pending_dir/etc/cron.d/yunohost-dyndns <<EOF
|
cat >$pending_dir/etc/cron.d/yunohost-dyndns <<EOF
|
||||||
SHELL=/bin/bash
|
SHELL=/bin/bash
|
||||||
# Every 10 minutes,
|
# Every 10 minutes,
|
||||||
|
@ -127,15 +119,18 @@ EOF
|
||||||
touch $pending_dir/etc/cron.d/yunohost-dyndns
|
touch $pending_dir/etc/cron.d/yunohost-dyndns
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# legacy stuff to avoid yunohost reporting etckeeper as manually modified
|
||||||
|
# (this make sure that the hash is null / file is flagged as to-delete)
|
||||||
|
mkdir -p $pending_dir/etc/etckeeper
|
||||||
|
touch $pending_dir/etc/etckeeper/etckeeper.conf
|
||||||
|
|
||||||
# Skip ntp if inside a container (inspired from the conf of systemd-timesyncd)
|
# Skip ntp if inside a container (inspired from the conf of systemd-timesyncd)
|
||||||
if systemctl | grep -q 'ntp.service'; then
|
|
||||||
mkdir -p ${pending_dir}/etc/systemd/system/ntp.service.d/
|
mkdir -p ${pending_dir}/etc/systemd/system/ntp.service.d/
|
||||||
cat > ${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf << EOF
|
echo "
|
||||||
[Unit]
|
[Unit]
|
||||||
ConditionCapability=CAP_SYS_TIME
|
ConditionCapability=CAP_SYS_TIME
|
||||||
ConditionVirtualization=!container
|
ConditionVirtualization=!container
|
||||||
EOF
|
" >${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf
|
||||||
fi
|
|
||||||
|
|
||||||
# Make nftable conflict with yunohost-firewall
|
# Make nftable conflict with yunohost-firewall
|
||||||
mkdir -p ${pending_dir}/etc/systemd/system/nftables.service.d/
|
mkdir -p ${pending_dir}/etc/systemd/system/nftables.service.d/
|
||||||
|
@ -156,16 +151,17 @@ HandleLidSwitchDocked=ignore
|
||||||
HandleLidSwitchExternalPower=ignore
|
HandleLidSwitchExternalPower=ignore
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cp yunohost-api.service ${pending_dir}/etc/systemd/system/yunohost-api.service
|
|
||||||
cp yunohost-firewall.service ${pending_dir}/etc/systemd/system/yunohost-firewall.service
|
|
||||||
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
|
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
|
||||||
|
|
||||||
|
if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]]; then
|
||||||
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||||
|
else
|
||||||
|
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p ${pending_dir}/etc/dpkg/origins/
|
mkdir -p ${pending_dir}/etc/dpkg/origins/
|
||||||
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
|
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
|
||||||
|
|
||||||
# Remove legacy hackish/clumsy nodejs autoupdate which ends up filling up space with ambiguous upgrades >_>
|
|
||||||
touch "/etc/cron.daily/node_update"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
|
@ -175,26 +171,17 @@ do_post_regen() {
|
||||||
# Enfore permissions #
|
# Enfore permissions #
|
||||||
######################
|
######################
|
||||||
|
|
||||||
chmod 770 /home/yunohost.backup
|
chmod 750 /home/admin
|
||||||
chmod 770 /home/yunohost.backup/archives
|
chmod 750 /home/yunohost.conf
|
||||||
chmod 700 /var/cache/yunohost
|
chmod 750 /home/yunohost.backup
|
||||||
chown root:admins /home/yunohost.backup
|
chmod 750 /home/yunohost.backup/archives
|
||||||
chown root:admins /home/yunohost.backup/archives
|
chown root:root /home/yunohost.conf
|
||||||
chown root:root /var/cache/yunohost
|
chown admin:root /home/yunohost.backup
|
||||||
|
chown admin:root /home/yunohost.backup/archives
|
||||||
[ ! -e /var/www/.well-known/ynh-diagnosis/ ] || chmod 775 /var/www/.well-known/ynh-diagnosis/
|
|
||||||
|
|
||||||
# NB: x permission for 'others' is important for ssl-cert (and maybe mdns), otherwise slapd will fail to start because can't access the certs
|
# NB: x permission for 'others' is important for ssl-cert (and maybe mdns), otherwise slapd will fail to start because can't access the certs
|
||||||
chmod 755 /etc/yunohost
|
chmod 755 /etc/yunohost
|
||||||
|
|
||||||
find /etc/systemd/system/*.service -type f | xargs -r chown root:root
|
|
||||||
find /etc/systemd/system/*.service -type f | xargs -r chmod 0644
|
|
||||||
|
|
||||||
if ls -l /etc/php/*/fpm/pool.d/*.conf; then
|
|
||||||
chown root:root /etc/php/*/fpm/pool.d/*.conf
|
|
||||||
chmod 644 /etc/php/*/fpm/pool.d/*.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Certs
|
# Certs
|
||||||
# We do this with find because there could be a lot of them...
|
# We do this with find because there could be a lot of them...
|
||||||
chown -R root:ssl-cert /etc/yunohost/certs
|
chown -R root:ssl-cert /etc/yunohost/certs
|
||||||
|
@ -206,6 +193,11 @@ do_post_regen() {
|
||||||
find /etc/cron.d/yunohost-* -type f -exec chmod 644 {} \;
|
find /etc/cron.d/yunohost-* -type f -exec chmod 644 {} \;
|
||||||
find /etc/cron.*/yunohost-* -type f -exec chown root:root {} \;
|
find /etc/cron.*/yunohost-* -type f -exec chown root:root {} \;
|
||||||
|
|
||||||
|
chown root:root /var/cache/yunohost
|
||||||
|
chmod 700 /var/cache/yunohost
|
||||||
|
chown root:root /var/cache/moulinette
|
||||||
|
chmod 700 /var/cache/moulinette
|
||||||
|
|
||||||
setfacl -m g:all_users:--- /var/www
|
setfacl -m g:all_users:--- /var/www
|
||||||
setfacl -m g:all_users:--- /var/log/nginx
|
setfacl -m g:all_users:--- /var/log/nginx
|
||||||
setfacl -m g:all_users:--- /etc/yunohost
|
setfacl -m g:all_users:--- /etc/yunohost
|
||||||
|
@ -219,7 +211,7 @@ do_post_regen() {
|
||||||
mkdir -p /etc/yunohost/domains
|
mkdir -p /etc/yunohost/domains
|
||||||
|
|
||||||
# Misc configuration / state files
|
# Misc configuration / state files
|
||||||
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2> /dev/null | grep -vw mdns.yml)
|
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null)
|
||||||
chmod 600 $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null)
|
chmod 600 $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null)
|
||||||
|
|
||||||
# Apps folder, custom hooks folder
|
# Apps folder, custom hooks folder
|
||||||
|
@ -232,20 +224,12 @@ do_post_regen() {
|
||||||
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
|
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
|
||||||
|
|
||||||
# Propagates changes in systemd service config overrides
|
# Propagates changes in systemd service config overrides
|
||||||
if systemctl | grep -q 'ntp.service'; then
|
|
||||||
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
|
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl restart ntp
|
systemctl restart ntp
|
||||||
}
|
}
|
||||||
fi
|
|
||||||
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
|
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||||
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || {
|
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl restart systemd-logind
|
|
||||||
}
|
|
||||||
[[ ! "$regen_conf_files" =~ "yunohost-firewall.service" ]] || systemctl daemon-reload
|
|
||||||
[[ ! "$regen_conf_files" =~ "yunohost-api.service" ]] || systemctl daemon-reload
|
|
||||||
|
|
||||||
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
|
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
|
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
|
||||||
|
@ -259,14 +243,11 @@ do_post_regen() {
|
||||||
|
|
||||||
# Change dpkg vendor
|
# Change dpkg vendor
|
||||||
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
|
||||||
if readlink -f /etc/dpkg/origins/default | grep -q debian; then
|
if readlink -f /etc/dpkg/origins/default | grep -q debian;
|
||||||
|
then
|
||||||
rm -f /etc/dpkg/origins/default
|
rm -f /etc/dpkg/origins/default
|
||||||
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -e /etc/yunohost/installed && test -e /etc/profile.d/check_yunohost_is_installed.sh; then
|
|
||||||
rm /etc/profile.d/check_yunohost_is_installed.sh
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_$1_regen ${@:2}
|
do_$1_regen ${@:2}
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
ssl_dir="/usr/share/yunohost/ssl"
|
ssl_dir="/usr/share/yunohost/yunohost-config/ssl/yunoCA"
|
||||||
template_dir="/usr/share/yunohost/conf/ssl"
|
|
||||||
ynh_ca="/etc/yunohost/certs/yunohost.org/ca.pem"
|
ynh_ca="/etc/yunohost/certs/yunohost.org/ca.pem"
|
||||||
ynh_crt="/etc/yunohost/certs/yunohost.org/crt.pem"
|
ynh_crt="/etc/yunohost/certs/yunohost.org/crt.pem"
|
||||||
ynh_key="/etc/yunohost/certs/yunohost.org/key.pem"
|
ynh_key="/etc/yunohost/certs/yunohost.org/key.pem"
|
||||||
|
openssl_conf="/usr/share/yunohost/templates/ssl/openssl.cnf"
|
||||||
|
|
||||||
regen_local_ca() {
|
regen_local_ca() {
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ regen_local_ca() {
|
||||||
RANDFILE=.rnd openssl rand -hex 19 >serial
|
RANDFILE=.rnd openssl rand -hex 19 >serial
|
||||||
rm -f index.txt
|
rm -f index.txt
|
||||||
touch index.txt
|
touch index.txt
|
||||||
cp ${template_dir}/openssl.cnf openssl.ca.cnf
|
cp /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf
|
||||||
sed -i "s/yunohost.org/${domain}/g" openssl.ca.cnf
|
sed -i "s/yunohost.org/${domain}/g" openssl.ca.cnf
|
||||||
openssl req -x509 \
|
openssl req -x509 \
|
||||||
-new \
|
-new \
|
||||||
|
@ -56,8 +56,8 @@ do_init_regen() {
|
||||||
chmod 640 $LOGFILE
|
chmod 640 $LOGFILE
|
||||||
|
|
||||||
# Make sure this conf exists
|
# Make sure this conf exists
|
||||||
mkdir -p ${ssl_dir}/{ca,certs,crl,newcerts}
|
mkdir -p ${ssl_dir}
|
||||||
install -D -m 644 ${template_dir}/openssl.cnf "${ssl_dir}/openssl.cnf"
|
cp /usr/share/yunohost/templates/ssl/openssl.cnf ${ssl_dir}/openssl.ca.cnf
|
||||||
|
|
||||||
# create default certificates
|
# create default certificates
|
||||||
if [[ ! -f "$ynh_ca" ]]; then
|
if [[ ! -f "$ynh_ca" ]]; then
|
||||||
|
@ -68,13 +68,14 @@ do_init_regen() {
|
||||||
echo -e "\n# Creating initial key and certificate \n" >>$LOGFILE
|
echo -e "\n# Creating initial key and certificate \n" >>$LOGFILE
|
||||||
|
|
||||||
openssl req -new \
|
openssl req -new \
|
||||||
-config "${ssl_dir}/openssl.cnf" \
|
-config "$openssl_conf" \
|
||||||
|
-days 730 \
|
||||||
-out "${ssl_dir}/certs/yunohost_csr.pem" \
|
-out "${ssl_dir}/certs/yunohost_csr.pem" \
|
||||||
-keyout "${ssl_dir}/certs/yunohost_key.pem" \
|
-keyout "${ssl_dir}/certs/yunohost_key.pem" \
|
||||||
-nodes -batch &>>$LOGFILE
|
-nodes -batch &>>$LOGFILE
|
||||||
|
|
||||||
openssl ca \
|
openssl ca \
|
||||||
-config "${ssl_dir}/openssl.cnf" \
|
-config "$openssl_conf" \
|
||||||
-days 730 \
|
-days 730 \
|
||||||
-in "${ssl_dir}/certs/yunohost_csr.pem" \
|
-in "${ssl_dir}/certs/yunohost_csr.pem" \
|
||||||
-out "${ssl_dir}/certs/yunohost_crt.pem" \
|
-out "${ssl_dir}/certs/yunohost_crt.pem" \
|
||||||
|
@ -91,12 +92,16 @@ do_init_regen() {
|
||||||
|
|
||||||
chown -R root:ssl-cert /etc/yunohost/certs/yunohost.org/
|
chown -R root:ssl-cert /etc/yunohost/certs/yunohost.org/
|
||||||
chmod o-rwx /etc/yunohost/certs/yunohost.org/
|
chmod o-rwx /etc/yunohost/certs/yunohost.org/
|
||||||
|
|
||||||
|
install -D -m 644 $openssl_conf "${ssl_dir}/openssl.cnf"
|
||||||
}
|
}
|
||||||
|
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
install -D -m 644 $template_dir/openssl.cnf "${pending_dir}/${ssl_dir}/openssl.cnf"
|
cd /usr/share/yunohost/templates/ssl
|
||||||
|
|
||||||
|
install -D -m 644 openssl.cnf "${pending_dir}/${ssl_dir}/openssl.cnf"
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
|
@ -105,28 +110,11 @@ do_post_regen() {
|
||||||
current_local_ca_domain=$(openssl x509 -in $ynh_ca -text | tr ',' '\n' | grep Issuer | awk '{print $4}')
|
current_local_ca_domain=$(openssl x509 -in $ynh_ca -text | tr ',' '\n' | grep Issuer | awk '{print $4}')
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
|
|
||||||
# Automigrate legacy folder
|
|
||||||
if [ -e /usr/share/yunohost/yunohost-config/ssl/yunoCA ]; then
|
|
||||||
mv /usr/share/yunohost/yunohost-config/ssl/yunoCA/* ${ssl_dir}
|
|
||||||
rm -rf /usr/share/yunohost/yunohost-config
|
|
||||||
# Overwrite openssl.cnf because it may still contain references to the old yunoCA dir
|
|
||||||
install -D -m 644 ${template_dir}/openssl.cnf "${ssl_dir}/openssl.cnf"
|
|
||||||
install -D -m 644 ${template_dir}/openssl.cnf "${ssl_dir}/openssl.ca.cnf"
|
|
||||||
sed -i "s/yunohost.org/${main_domain}/g" openssl.ca.cnf
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p ${ssl_dir}/{ca,certs,crl,newcerts}
|
|
||||||
chown root:root ${ssl_dir}
|
|
||||||
chmod 750 ${ssl_dir}
|
|
||||||
chmod -R o-rwx ${ssl_dir}
|
|
||||||
chmod o+x ${ssl_dir}/certs
|
|
||||||
chmod o+r ${ssl_dir}/certs/yunohost_crt.pem
|
|
||||||
|
|
||||||
if [[ "$current_local_ca_domain" != "$main_domain" ]]; then
|
if [[ "$current_local_ca_domain" != "$main_domain" ]]; then
|
||||||
regen_local_ca $main_domain
|
regen_local_ca $main_domain
|
||||||
# Idk how useful this is, but this was in the previous python code (domain.main_domain())
|
# Idk how useful this is, but this was in the previous python code (domain.main_domain())
|
||||||
ln -sf /etc/yunohost/certs/$main_domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
|
ln -sf /etc/yunohost/certs/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
|
||||||
ln -sf /etc/yunohost/certs/$main_domain/key.pem /etc/ssl/private/yunohost_key.pem
|
ln -sf /etc/yunohost/certs/$domain/key.pem /etc/ssl/private/yunohost_key.pem
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,26 @@ set -e
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/ssh
|
# If the (legacy) 'from_script' flag is here,
|
||||||
|
# we won't touch anything in the ssh config.
|
||||||
|
[[ ! -f /etc/yunohost/from_script ]] || return 0
|
||||||
|
|
||||||
|
cd /usr/share/yunohost/templates/ssh
|
||||||
|
|
||||||
# do not listen to IPv6 if unavailable
|
# do not listen to IPv6 if unavailable
|
||||||
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
|
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
|
||||||
|
|
||||||
ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null || true)
|
ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null || true)
|
||||||
|
|
||||||
|
# Support legacy setting (this setting might be disabled by a user during a migration)
|
||||||
|
if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then
|
||||||
|
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
# Support different strategy for security configurations
|
# Support different strategy for security configurations
|
||||||
export compatibility="$(yunohost settings get 'security.ssh.ssh_compatibility')"
|
export compatibility="$(yunohost settings get 'security.ssh.compatibility')"
|
||||||
export port="$(yunohost settings get 'security.ssh.ssh_port')"
|
export port="$(yunohost settings get 'security.ssh.port')"
|
||||||
export password_authentication="$(yunohost settings get 'security.ssh.ssh_password_authentication' | int_to_bool)"
|
export password_authentication="$(yunohost settings get 'security.ssh.password_authentication')"
|
||||||
export ssh_keys
|
export ssh_keys
|
||||||
export ipv6_enabled
|
export ipv6_enabled
|
||||||
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
|
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
|
||||||
|
@ -26,6 +35,10 @@ do_pre_regen() {
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
|
# If the (legacy) 'from_script' flag is here,
|
||||||
|
# we won't touch anything in the ssh config.
|
||||||
|
[[ ! -f /etc/yunohost/from_script ]] || return 0
|
||||||
|
|
||||||
# If no file changed, there's nothing to do
|
# If no file changed, there's nothing to do
|
||||||
[[ -n "$regen_conf_files" ]] || return 0
|
[[ -n "$regen_conf_files" ]] || return 0
|
||||||
|
|
|
@ -4,8 +4,8 @@ set -e
|
||||||
|
|
||||||
tmp_backup_dir_file="/root/slapd-backup-dir.txt"
|
tmp_backup_dir_file="/root/slapd-backup-dir.txt"
|
||||||
|
|
||||||
config="/usr/share/yunohost/conf/slapd/config.ldif"
|
config="/usr/share/yunohost/templates/slapd/config.ldif"
|
||||||
db_init="/usr/share/yunohost/conf/slapd/db_init.ldif"
|
db_init="/usr/share/yunohost/templates/slapd/db_init.ldif"
|
||||||
|
|
||||||
do_init_regen() {
|
do_init_regen() {
|
||||||
if [[ $EUID -ne 0 ]]; then
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
@ -58,6 +58,14 @@ EOF
|
||||||
nscd -i passwd || true
|
nscd -i passwd || true
|
||||||
|
|
||||||
systemctl restart slapd
|
systemctl restart slapd
|
||||||
|
|
||||||
|
# We don't use mkhomedir_helper because 'admin' may not be recognized
|
||||||
|
# when this script is ran in a chroot (e.g. ISO install)
|
||||||
|
# We also refer to admin as uid 1007 for the same reason
|
||||||
|
if [ ! -d /home/admin ]; then
|
||||||
|
cp -r /etc/skel /home/admin
|
||||||
|
chown -R 1007:1007 /home/admin
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_regenerate_slapd_conf() {
|
_regenerate_slapd_conf() {
|
||||||
|
@ -101,7 +109,12 @@ do_pre_regen() {
|
||||||
schema_dir="${ldap_dir}/schema"
|
schema_dir="${ldap_dir}/schema"
|
||||||
mkdir -p "$ldap_dir" "$schema_dir"
|
mkdir -p "$ldap_dir" "$schema_dir"
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/slapd
|
# remove legacy configuration file
|
||||||
|
[ ! -f /etc/ldap/slapd-yuno.conf ] || touch "${ldap_dir}/slapd-yuno.conf"
|
||||||
|
[ ! -f /etc/ldap/slapd.conf ] || touch "${ldap_dir}/slapd.conf"
|
||||||
|
[ ! -f /etc/ldap/schema/yunohost.schema ] || touch "${schema_dir}/yunohost.schema"
|
||||||
|
|
||||||
|
cd /usr/share/yunohost/templates/slapd
|
||||||
|
|
||||||
# copy configuration files
|
# copy configuration files
|
||||||
cp -a ldap.conf "$ldap_dir"
|
cp -a ldap.conf "$ldap_dir"
|
||||||
|
@ -123,10 +136,6 @@ do_post_regen() {
|
||||||
chown -R openldap:openldap /etc/ldap/schema/
|
chown -R openldap:openldap /etc/ldap/schema/
|
||||||
chown -R openldap:openldap /etc/ldap/slapd.d/
|
chown -R openldap:openldap /etc/ldap/slapd.d/
|
||||||
|
|
||||||
# Fix weird scenarios where /etc/sudo-ldap.conf doesn't exists (yet is supposed to be
|
|
||||||
# created by the sudo-ldap package) : https://github.com/YunoHost/issues/issues/2091
|
|
||||||
[ -e /etc/sudo-ldap.conf ] || ln -s /etc/ldap/ldap.conf /etc/sudo-ldap.conf
|
|
||||||
|
|
||||||
# If we changed the systemd ynh-override conf
|
# If we changed the systemd ynh-override conf
|
||||||
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$"; then
|
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$"; then
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
@ -135,7 +144,7 @@ do_post_regen() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For some reason, old setups don't have the admins group defined...
|
# For some reason, old setups don't have the admins group defined...
|
||||||
if ! slapcat -H "ldap:///cn=admins,ou=groups,dc=yunohost,dc=org" | grep -q 'cn=admins,ou=groups,dc=yunohost,dc=org'; then
|
if ! slapcat | grep -q 'cn=admins,ou=groups,dc=yunohost,dc=org'; then
|
||||||
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org <<< \
|
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org <<< \
|
||||||
"dn: cn=admins,ou=groups,dc=yunohost,dc=org
|
"dn: cn=admins,ou=groups,dc=yunohost,dc=org
|
||||||
cn: admins
|
cn: admins
|
||||||
|
@ -168,6 +177,22 @@ objectClass: top"
|
||||||
|
|
||||||
echo "Reloading slapd"
|
echo "Reloading slapd"
|
||||||
systemctl force-reload slapd
|
systemctl force-reload slapd
|
||||||
|
|
||||||
|
# on slow hardware/vm this regen conf would exit before the admin user that
|
||||||
|
# is stored in ldap is available because ldap seems to slow to restart
|
||||||
|
# so we'll wait either until we are able to log as admin or until a timeout
|
||||||
|
# is reached
|
||||||
|
# we need to do this because the next hooks executed after this one during
|
||||||
|
# postinstall requires to run as admin thus breaking postinstall on slow
|
||||||
|
# hardware which mean yunohost can't be correctly installed on those hardware
|
||||||
|
# and this sucks
|
||||||
|
# wait a maximum time of 5 minutes
|
||||||
|
# yes, force-reload behave like a restart
|
||||||
|
number_of_wait=0
|
||||||
|
while ! su admin -c '' && ((number_of_wait < 60)); do
|
||||||
|
sleep 5
|
||||||
|
((number_of_wait += 1))
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
do_$1_regen ${@:2}
|
do_$1_regen ${@:2}
|
|
@ -10,7 +10,7 @@ do_init_regen() {
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/nslcd
|
cd /usr/share/yunohost/templates/nslcd
|
||||||
|
|
||||||
install -D -m 644 nslcd.conf "${pending_dir}/etc/nslcd.conf"
|
install -D -m 644 nslcd.conf "${pending_dir}/etc/nslcd.conf"
|
||||||
}
|
}
|
61
data/hooks/conf_regen/10-apt
Executable file
61
data/hooks/conf_regen/10-apt
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
do_pre_regen() {
|
||||||
|
pending_dir=$1
|
||||||
|
|
||||||
|
mkdir --parents "${pending_dir}/etc/apt/preferences.d"
|
||||||
|
|
||||||
|
echo "
|
||||||
|
Package: php-common
|
||||||
|
Pin: origin \"packages.sury.org\"
|
||||||
|
Pin-Priority: 500" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
||||||
|
|
||||||
|
packages_to_refuse_from_sury="php php-* openssl libssl1.1 libssl-dev"
|
||||||
|
for package in $packages_to_refuse_from_sury; do
|
||||||
|
echo "
|
||||||
|
Package: $package
|
||||||
|
Pin: origin \"packages.sury.org\"
|
||||||
|
Pin-Priority: -1" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "
|
||||||
|
|
||||||
|
# PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
|
||||||
|
|
||||||
|
# You are probably reading this file because you tried to install apache2 or
|
||||||
|
# bind9. These 2 packages conflict with YunoHost.
|
||||||
|
|
||||||
|
# Installing apache2 will break nginx and break the entire YunoHost ecosystem
|
||||||
|
# on your server, therefore don't remove those lines!
|
||||||
|
|
||||||
|
# You have been warned.
|
||||||
|
|
||||||
|
Package: apache2
|
||||||
|
Pin: release *
|
||||||
|
Pin-Priority: -1
|
||||||
|
|
||||||
|
Package: apache2-bin
|
||||||
|
Pin: release *
|
||||||
|
Pin-Priority: -1
|
||||||
|
|
||||||
|
# Also bind9 will conflict with dnsmasq.
|
||||||
|
# Same story as for apache2.
|
||||||
|
# Don't install it, don't remove those lines.
|
||||||
|
|
||||||
|
Package: bind9
|
||||||
|
Pin: release *
|
||||||
|
Pin-Priority: -1
|
||||||
|
" >>"${pending_dir}/etc/apt/preferences.d/ban_packages"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_post_regen() {
|
||||||
|
regen_conf_files=$1
|
||||||
|
|
||||||
|
# Make sure php7.3 is the default version when using php in cli
|
||||||
|
update-alternatives --set php /usr/bin/php7.3
|
||||||
|
}
|
||||||
|
|
||||||
|
do_$1_regen ${@:2}
|
|
@ -2,15 +2,10 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if ! dpkg --list | grep -q 'ii *metronome '; then
|
|
||||||
echo 'metronome is not installed, skipping'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/metronome
|
cd /usr/share/yunohost/templates/metronome
|
||||||
|
|
||||||
# create directories for pending conf
|
# create directories for pending conf
|
||||||
metronome_dir="${pending_dir}/etc/metronome"
|
metronome_dir="${pending_dir}/etc/metronome"
|
||||||
|
@ -25,14 +20,8 @@ do_pre_regen() {
|
||||||
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
||||||
>"${metronome_dir}/metronome.cfg.lua"
|
>"${metronome_dir}/metronome.cfg.lua"
|
||||||
|
|
||||||
# Trick such that old conf files are flagged as to remove
|
|
||||||
for domain in $YNH_DOMAINS; do
|
|
||||||
touch "${metronome_conf_dir}/${domain}.cfg.lua"
|
|
||||||
done
|
|
||||||
|
|
||||||
# add domain conf files
|
# add domain conf files
|
||||||
domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")"
|
for domain in $YNH_DOMAINS; do
|
||||||
for domain in $domain_list; do
|
|
||||||
cat domain.tpl.cfg.lua \
|
cat domain.tpl.cfg.lua \
|
||||||
| sed "s/{{ domain }}/${domain}/g" \
|
| sed "s/{{ domain }}/${domain}/g" \
|
||||||
>"${metronome_conf_dir}/${domain}.cfg.lua"
|
>"${metronome_conf_dir}/${domain}.cfg.lua"
|
||||||
|
@ -54,8 +43,12 @@ do_post_regen() {
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
|
|
||||||
|
# FIXME : small optimization to do to avoid calling a yunohost command ...
|
||||||
|
# maybe another env variable like YNH_MAIN_DOMAINS idk
|
||||||
|
domain_list=$(yunohost domain list --exclude-subdomains --output-as plain --quiet)
|
||||||
|
|
||||||
# create metronome directories for domains
|
# create metronome directories for domains
|
||||||
for domain in $YNH_MAIN_DOMAINS; do
|
for domain in $domain_list; do
|
||||||
mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
|
mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
|
||||||
# http_upload directory must be writable by metronome and readable by nginx
|
# http_upload directory must be writable by metronome and readable by nginx
|
||||||
mkdir -p "/var/xmpp-upload/${domain}/upload"
|
mkdir -p "/var/xmpp-upload/${domain}/upload"
|
||||||
|
@ -73,19 +66,8 @@ do_post_regen() {
|
||||||
chown -R metronome: /var/lib/metronome/
|
chown -R metronome: /var/lib/metronome/
|
||||||
chown -R metronome: /etc/metronome/conf.d/
|
chown -R metronome: /etc/metronome/conf.d/
|
||||||
|
|
||||||
if [[ -z "$(ls /etc/metronome/conf.d/*.cfg.lua 2> /dev/null)" ]]; then
|
|
||||||
if systemctl is-enabled metronome &> /dev/null; then
|
|
||||||
systemctl disable metronome --now 2> /dev/null
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if ! systemctl is-enabled metronome &> /dev/null; then
|
|
||||||
systemctl enable metronome --now 2> /dev/null
|
|
||||||
sleep 3
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ -z "$regen_conf_files" ]] \
|
[[ -z "$regen_conf_files" ]] \
|
||||||
|| systemctl restart metronome
|
|| systemctl restart metronome
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_$1_regen ${@:2}
|
do_$1_regen ${@:2}
|
|
@ -10,7 +10,7 @@ do_init_regen() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/nginx
|
cd /usr/share/yunohost/templates/nginx
|
||||||
|
|
||||||
nginx_dir="/etc/nginx"
|
nginx_dir="/etc/nginx"
|
||||||
nginx_conf_dir="${nginx_dir}/conf.d"
|
nginx_conf_dir="${nginx_dir}/conf.d"
|
||||||
|
@ -47,7 +47,7 @@ do_init_regen() {
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/nginx
|
cd /usr/share/yunohost/templates/nginx
|
||||||
|
|
||||||
nginx_dir="${pending_dir}/etc/nginx"
|
nginx_dir="${pending_dir}/etc/nginx"
|
||||||
nginx_conf_dir="${nginx_dir}/conf.d"
|
nginx_conf_dir="${nginx_dir}/conf.d"
|
||||||
|
@ -56,8 +56,8 @@ do_pre_regen() {
|
||||||
# install / update plain conf files
|
# install / update plain conf files
|
||||||
cp plain/* "$nginx_conf_dir"
|
cp plain/* "$nginx_conf_dir"
|
||||||
# remove the panel overlay if this is specified in settings
|
# remove the panel overlay if this is specified in settings
|
||||||
panel_overlay=$(yunohost settings get 'misc.portal.ssowat_panel_overlay_enabled' | int_to_bool)
|
panel_overlay=$(yunohost settings get 'ssowat.panel_overlay.enabled')
|
||||||
if [ "$panel_overlay" == "False" ]; then
|
if [ "$panel_overlay" == "false" ] || [ "$panel_overlay" == "False" ]; then
|
||||||
echo "#" >"${nginx_conf_dir}/yunohost_panel.conf.inc"
|
echo "#" >"${nginx_conf_dir}/yunohost_panel.conf.inc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -65,16 +65,14 @@ do_pre_regen() {
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
|
|
||||||
# Support different strategy for security configurations
|
# Support different strategy for security configurations
|
||||||
export redirect_to_https="$(yunohost settings get 'security.nginx.nginx_redirect_to_https' | int_to_bool)"
|
export redirect_to_https="$(yunohost settings get 'security.nginx.redirect_to_https')"
|
||||||
export compatibility="$(yunohost settings get 'security.nginx.nginx_compatibility')"
|
export compatibility="$(yunohost settings get 'security.nginx.compatibility')"
|
||||||
export experimental="$(yunohost settings get 'security.experimental.security_experimental_enabled' | int_to_bool)"
|
export experimental="$(yunohost settings get 'security.experimental.enabled')"
|
||||||
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
|
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
|
||||||
|
|
||||||
cert_status=$(yunohost domain cert status --json)
|
cert_status=$(yunohost domain cert status --json)
|
||||||
|
|
||||||
# add domain conf files
|
# add domain conf files
|
||||||
xmpp_domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")"
|
|
||||||
mail_domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]")"
|
|
||||||
for domain in $YNH_DOMAINS; do
|
for domain in $YNH_DOMAINS; do
|
||||||
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
|
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
|
||||||
mkdir -p "$domain_conf_dir"
|
mkdir -p "$domain_conf_dir"
|
||||||
|
@ -86,29 +84,17 @@ do_pre_regen() {
|
||||||
export domain_cert_ca=$(echo $cert_status \
|
export domain_cert_ca=$(echo $cert_status \
|
||||||
| jq ".certificates.\"$domain\".CA_type" \
|
| jq ".certificates.\"$domain\".CA_type" \
|
||||||
| tr -d '"')
|
| tr -d '"')
|
||||||
if echo "$xmpp_domain_list" | grep -q "^$domain$"; then
|
|
||||||
export xmpp_enabled="True"
|
|
||||||
else
|
|
||||||
export xmpp_enabled="False"
|
|
||||||
fi
|
|
||||||
if echo "$mail_domain_list" | grep -q "^$domain$"; then
|
|
||||||
export mail_enabled="True"
|
|
||||||
else
|
|
||||||
export mail_enabled="False"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ynh_render_template "server.tpl.conf" "${nginx_conf_dir}/${domain}.conf"
|
ynh_render_template "server.tpl.conf" "${nginx_conf_dir}/${domain}.conf"
|
||||||
if [ $mail_enabled == "True" ]; then
|
|
||||||
ynh_render_template "autoconfig.tpl.xml" "${mail_autoconfig_dir}/config-v1.1.xml"
|
ynh_render_template "autoconfig.tpl.xml" "${mail_autoconfig_dir}/config-v1.1.xml"
|
||||||
fi
|
|
||||||
|
|
||||||
touch "${domain_conf_dir}/yunohost_local.conf" # Clean legacy conf files
|
touch "${domain_conf_dir}/yunohost_local.conf" # Clean legacy conf files
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.webadmin_allowlist_enabled | int_to_bool)
|
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.allowlist.enabled)
|
||||||
if [ "$webadmin_allowlist_enabled" == "True" ]; then
|
if [ "$webadmin_allowlist_enabled" == "True" ]; then
|
||||||
export webadmin_allowlist=$(yunohost settings get security.webadmin.webadmin_allowlist)
|
export webadmin_allowlist=$(yunohost settings get security.webadmin.allowlist)
|
||||||
fi
|
fi
|
||||||
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
|
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
|
||||||
ynh_render_template "yunohost_api.conf.inc" "${nginx_conf_dir}/yunohost_api.conf.inc"
|
ynh_render_template "yunohost_api.conf.inc" "${nginx_conf_dir}/yunohost_api.conf.inc"
|
||||||
|
@ -141,11 +127,6 @@ do_pre_regen() {
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
if ls -l /etc/nginx/conf.d/*.d/*.conf; then
|
|
||||||
chown root:root /etc/nginx/conf.d/*.d/*.conf
|
|
||||||
chmod 644 /etc/nginx/conf.d/*.d/*.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -z "$regen_conf_files" ] && exit 0
|
[ -z "$regen_conf_files" ] && exit 0
|
||||||
|
|
||||||
# create NGINX conf directories for domains
|
# create NGINX conf directories for domains
|
||||||
|
@ -153,6 +134,18 @@ do_post_regen() {
|
||||||
mkdir -p "/etc/nginx/conf.d/${domain}.d"
|
mkdir -p "/etc/nginx/conf.d/${domain}.d"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Get rid of legacy lets encrypt snippets
|
||||||
|
for domain in $YNH_DOMAINS; do
|
||||||
|
# If the legacy letsencrypt / acme-challenge domain-specific snippet is still there
|
||||||
|
if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ]; then
|
||||||
|
# And if we're effectively including the new domain-independant snippet now
|
||||||
|
if grep -q "include /etc/nginx/conf.d/acme-challenge.conf.inc;" /etc/nginx/conf.d/${domain}.conf; then
|
||||||
|
# Delete the old domain-specific snippet
|
||||||
|
rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Reload nginx if conf looks good, otherwise display error and exit unhappy
|
# Reload nginx if conf looks good, otherwise display error and exit unhappy
|
||||||
nginx -t 2>/dev/null || {
|
nginx -t 2>/dev/null || {
|
||||||
nginx -t
|
nginx -t
|
81
data/hooks/conf_regen/19-postfix
Executable file
81
data/hooks/conf_regen/19-postfix
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. /usr/share/yunohost/helpers
|
||||||
|
|
||||||
|
do_pre_regen() {
|
||||||
|
pending_dir=$1
|
||||||
|
|
||||||
|
cd /usr/share/yunohost/templates/postfix
|
||||||
|
|
||||||
|
postfix_dir="${pending_dir}/etc/postfix"
|
||||||
|
mkdir -p "$postfix_dir"
|
||||||
|
|
||||||
|
default_dir="${pending_dir}/etc/default/"
|
||||||
|
mkdir -p "$default_dir"
|
||||||
|
|
||||||
|
# install plain conf files
|
||||||
|
cp plain/* "$postfix_dir"
|
||||||
|
|
||||||
|
# prepare main.cf conf file
|
||||||
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
|
|
||||||
|
# Support different strategy for security configurations
|
||||||
|
export compatibility="$(yunohost settings get 'security.postfix.compatibility')"
|
||||||
|
|
||||||
|
# Add possibility to specify a relay
|
||||||
|
# Could be useful with some isp with no 25 port open or more complex setup
|
||||||
|
export relay_port=""
|
||||||
|
export relay_user=""
|
||||||
|
export relay_host="$(yunohost settings get 'smtp.relay.host')"
|
||||||
|
if [ -n "${relay_host}" ]; then
|
||||||
|
relay_port="$(yunohost settings get 'smtp.relay.port')"
|
||||||
|
relay_user="$(yunohost settings get 'smtp.relay.user')"
|
||||||
|
relay_password="$(yunohost settings get 'smtp.relay.password')"
|
||||||
|
|
||||||
|
# Avoid to display "Relay account paswword" to other users
|
||||||
|
touch ${postfix_dir}/sasl_passwd
|
||||||
|
chmod 750 ${postfix_dir}/sasl_passwd
|
||||||
|
# Avoid "postmap: warning: removing zero-length database file"
|
||||||
|
chown postfix ${pending_dir}/etc/postfix
|
||||||
|
chown postfix ${pending_dir}/etc/postfix/sasl_passwd
|
||||||
|
|
||||||
|
cat <<<"[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" >${postfix_dir}/sasl_passwd
|
||||||
|
postmap ${postfix_dir}/sasl_passwd
|
||||||
|
fi
|
||||||
|
export main_domain
|
||||||
|
export domain_list="$YNH_DOMAINS"
|
||||||
|
ynh_render_template "main.cf" "${postfix_dir}/main.cf"
|
||||||
|
|
||||||
|
cat postsrsd \
|
||||||
|
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
||||||
|
| sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \
|
||||||
|
>"${default_dir}/postsrsd"
|
||||||
|
|
||||||
|
# adapt it for IPv4-only hosts
|
||||||
|
ipv6="$(yunohost settings get 'smtp.allow_ipv6')"
|
||||||
|
if [ "$ipv6" == "False" ] || [ ! -f /proc/net/if_inet6 ]; then
|
||||||
|
sed -i \
|
||||||
|
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
|
||||||
|
"${postfix_dir}/main.cf"
|
||||||
|
sed -i \
|
||||||
|
's/inet_interfaces = all/&\ninet_protocols = ipv4/' \
|
||||||
|
"${postfix_dir}/main.cf"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_post_regen() {
|
||||||
|
regen_conf_files=$1
|
||||||
|
|
||||||
|
if [ -e /etc/postfix/sasl_passwd ]; then
|
||||||
|
chmod 750 /etc/postfix/sasl_passwd*
|
||||||
|
chown postfix:root /etc/postfix/sasl_passwd*
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$regen_conf_files" ]] \
|
||||||
|
|| { systemctl restart postfix && systemctl restart postsrsd; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_$1_regen ${@:2}
|
|
@ -7,7 +7,7 @@ set -e
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/dovecot
|
cd /usr/share/yunohost/templates/dovecot
|
||||||
|
|
||||||
dovecot_dir="${pending_dir}/etc/dovecot"
|
dovecot_dir="${pending_dir}/etc/dovecot"
|
||||||
mkdir -p "${dovecot_dir}/global_script"
|
mkdir -p "${dovecot_dir}/global_script"
|
||||||
|
@ -16,9 +16,8 @@ do_pre_regen() {
|
||||||
cp dovecot-ldap.conf "${dovecot_dir}/dovecot-ldap.conf"
|
cp dovecot-ldap.conf "${dovecot_dir}/dovecot-ldap.conf"
|
||||||
cp dovecot.sieve "${dovecot_dir}/global_script/dovecot.sieve"
|
cp dovecot.sieve "${dovecot_dir}/global_script/dovecot.sieve"
|
||||||
|
|
||||||
export pop3_enabled="$(yunohost settings get 'email.pop3.pop3_enabled' | int_to_bool)"
|
export pop3_enabled="$(yunohost settings get 'pop3.enabled')"
|
||||||
export main_domain=$(cat /etc/yunohost/current_host)
|
export main_domain=$(cat /etc/yunohost/current_host)
|
||||||
export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
|
|
||||||
|
|
||||||
ynh_render_template "dovecot.conf" "${dovecot_dir}/dovecot.conf"
|
ynh_render_template "dovecot.conf" "${dovecot_dir}/dovecot.conf"
|
||||||
|
|
||||||
|
@ -53,8 +52,6 @@ do_post_regen() {
|
||||||
chown root:mail /var/mail
|
chown root:mail /var/mail
|
||||||
chmod 1775 /var/mail
|
chmod 1775 /var/mail
|
||||||
|
|
||||||
python3 -c 'from yunohost.app import regen_mail_app_user_config_for_dovecot_and_postfix as r; r(only="dovecot")'
|
|
||||||
|
|
||||||
[ -z "$regen_conf_files" ] && exit 0
|
[ -z "$regen_conf_files" ] && exit 0
|
||||||
|
|
||||||
# compile sieve script
|
# compile sieve script
|
|
@ -5,7 +5,7 @@ set -e
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/rspamd
|
cd /usr/share/yunohost/templates/rspamd
|
||||||
|
|
||||||
install -D -m 644 metrics.local.conf \
|
install -D -m 644 metrics.local.conf \
|
||||||
"${pending_dir}/etc/rspamd/local.d/metrics.conf"
|
"${pending_dir}/etc/rspamd/local.d/metrics.conf"
|
||||||
|
@ -13,8 +13,6 @@ do_pre_regen() {
|
||||||
"${pending_dir}/etc/rspamd/local.d/dkim_signing.conf"
|
"${pending_dir}/etc/rspamd/local.d/dkim_signing.conf"
|
||||||
install -D -m 644 rspamd.sieve \
|
install -D -m 644 rspamd.sieve \
|
||||||
"${pending_dir}/etc/dovecot/global_script/rspamd.sieve"
|
"${pending_dir}/etc/dovecot/global_script/rspamd.sieve"
|
||||||
install -D -m 644 redis.conf \
|
|
||||||
"${pending_dir}/etc/rspamd/local.d/redis.conf"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
|
@ -28,8 +26,7 @@ do_post_regen() {
|
||||||
chown _rspamd /etc/dkim
|
chown _rspamd /etc/dkim
|
||||||
|
|
||||||
# create DKIM key for domains
|
# create DKIM key for domains
|
||||||
domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')"
|
for domain in $YNH_DOMAINS; do
|
||||||
for domain in $domain_list; do
|
|
||||||
domain_key="/etc/dkim/${domain}.mail.key"
|
domain_key="/etc/dkim/${domain}.mail.key"
|
||||||
[ ! -f "$domain_key" ] && {
|
[ ! -f "$domain_key" ] && {
|
||||||
# We use a 1024 bit size because nsupdate doesn't seem to be able to
|
# We use a 1024 bit size because nsupdate doesn't seem to be able to
|
|
@ -3,17 +3,12 @@
|
||||||
set -e
|
set -e
|
||||||
. /usr/share/yunohost/helpers
|
. /usr/share/yunohost/helpers
|
||||||
|
|
||||||
if ! dpkg --list | grep -q 'ii *mariadb-server '; then
|
|
||||||
echo 'mysql/mariadb is not installed, skipping'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
#cd /usr/share/yunohost/conf/mysql
|
cd /usr/share/yunohost/templates/mysql
|
||||||
|
|
||||||
# Nothing to do
|
install -D -m 644 my.cnf "${pending_dir}/etc/mysql/my.cnf"
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
|
@ -34,6 +29,27 @@ do_post_regen() {
|
||||||
echo "" | mysql && echo "Can't connect to mysql using unix_socket auth ... something went wrong during initial configuration of mysql !?" >&2
|
echo "" | mysql && echo "Can't connect to mysql using unix_socket auth ... something went wrong during initial configuration of mysql !?" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Legacy code to get rid of /etc/yunohost/mysql ...
|
||||||
|
# Nowadays, we can simply run mysql while being run as root of unix_socket/auth_socket is enabled...
|
||||||
|
if [ -f /etc/yunohost/mysql ]; then
|
||||||
|
|
||||||
|
# This is a trick to check if we're able to use mysql without password
|
||||||
|
# Expect instances installed in stretch to already have unix_socket
|
||||||
|
#configured, but not old instances from the jessie/wheezy era
|
||||||
|
if ! echo "" | mysql 2>/dev/null; then
|
||||||
|
password="$(cat /etc/yunohost/mysql)"
|
||||||
|
# Enable plugin unix_socket for root on localhost
|
||||||
|
mysql -u root -p"$password" <<<"GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED WITH unix_socket WITH GRANT OPTION;"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If now we're able to login without password, drop the mysql password
|
||||||
|
if echo "" | mysql 2>/dev/null; then
|
||||||
|
rm /etc/yunohost/mysql
|
||||||
|
else
|
||||||
|
echo "Can't connect to mysql using unix_socket auth ... something went wrong while trying to get rid of mysql password !?" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# mysql is supposed to be an alias to mariadb... but in some weird case is not
|
# mysql is supposed to be an alias to mariadb... but in some weird case is not
|
||||||
# c.f. https://forum.yunohost.org/t/mysql-ne-fonctionne-pas/11661
|
# c.f. https://forum.yunohost.org/t/mysql-ne-fonctionne-pas/11661
|
||||||
# Playing with enable/disable allows to recreate the proper symlinks.
|
# Playing with enable/disable allows to recreate the proper symlinks.
|
|
@ -5,7 +5,8 @@ set -e
|
||||||
_generate_config() {
|
_generate_config() {
|
||||||
echo "domains:"
|
echo "domains:"
|
||||||
# Add yunohost.local (only if yunohost.local ain't already in ynh_domains)
|
# Add yunohost.local (only if yunohost.local ain't already in ynh_domains)
|
||||||
if ! echo "$YNH_DOMAINS" | tr ' ' '\n' | grep -q --line-regexp 'yunohost.local'; then
|
if ! echo "$YNH_DOMAINS" | tr ' ' '\n' | grep -q --line-regexp 'yunohost.local'
|
||||||
|
then
|
||||||
echo " - yunohost.local"
|
echo " - yunohost.local"
|
||||||
fi
|
fi
|
||||||
for domain in $YNH_DOMAINS; do
|
for domain in $YNH_DOMAINS; do
|
||||||
|
@ -14,8 +15,10 @@ _generate_config() {
|
||||||
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
|
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
|
||||||
echo " - $domain"
|
echo " - $domain"
|
||||||
done
|
done
|
||||||
if [[ -e /etc/yunohost/mdns.aliases ]]; then
|
if [[ -e /etc/yunohost/mdns.aliases ]]
|
||||||
for localalias in $(cat /etc/yunohost/mdns.aliases | grep -v "^ *$"); do
|
then
|
||||||
|
for localalias in $(cat /etc/yunohost/mdns.aliases | grep -v "^ *$")
|
||||||
|
do
|
||||||
echo " - $localalias.local"
|
echo " - $localalias.local"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
@ -24,13 +27,13 @@ _generate_config() {
|
||||||
do_init_regen() {
|
do_init_regen() {
|
||||||
do_pre_regen
|
do_pre_regen
|
||||||
do_post_regen /etc/systemd/system/yunomdns.service
|
do_post_regen /etc/systemd/system/yunomdns.service
|
||||||
systemctl enable yunomdns --quiet
|
systemctl enable yunomdns
|
||||||
}
|
}
|
||||||
|
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir="$1"
|
pending_dir="$1"
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/mdns
|
cd /usr/share/yunohost/templates/mdns
|
||||||
mkdir -p ${pending_dir}/etc/systemd/system/
|
mkdir -p ${pending_dir}/etc/systemd/system/
|
||||||
cp yunomdns.service ${pending_dir}/etc/systemd/system/
|
cp yunomdns.service ${pending_dir}/etc/systemd/system/
|
||||||
|
|
||||||
|
@ -50,9 +53,12 @@ do_post_regen() {
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
systemctl disable avahi-daemon.socket --now 2>&1|| true
|
||||||
|
systemctl disable avahi-daemon --now 2>&1 || true
|
||||||
|
|
||||||
# Legacy stuff to enable the new yunomdns service on legacy systems
|
# Legacy stuff to enable the new yunomdns service on legacy systems
|
||||||
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then
|
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then
|
||||||
systemctl enable yunomdns --now --quiet
|
systemctl enable yunomdns --now
|
||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -6,7 +6,7 @@ set -e
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/dnsmasq
|
cd /usr/share/yunohost/templates/dnsmasq
|
||||||
|
|
||||||
# create directory for pending conf
|
# create directory for pending conf
|
||||||
dnsmasq_dir="${pending_dir}/etc/dnsmasq.d"
|
dnsmasq_dir="${pending_dir}/etc/dnsmasq.d"
|
||||||
|
@ -21,9 +21,9 @@ do_pre_regen() {
|
||||||
cat plain/resolv.dnsmasq.conf | grep "^nameserver" | shuf >${pending_dir}/etc/resolv.dnsmasq.conf
|
cat plain/resolv.dnsmasq.conf | grep "^nameserver" | shuf >${pending_dir}/etc/resolv.dnsmasq.conf
|
||||||
|
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
ipv4=$(curl --max-time 10 -s -4 https://ip.yunohost.org 2> /dev/null || true)
|
ipv4=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
|
||||||
ynh_validate_ip4 "$ipv4" || ipv4='127.0.0.1'
|
ynh_validate_ip4 "$ipv4" || ipv4='127.0.0.1'
|
||||||
ipv6=$(curl --max-time 10 -s -6 https://ip6.yunohost.org 2> /dev/null || true)
|
ipv6=$(curl -s -6 https://ip6.yunohost.org 2>/dev/null || true)
|
||||||
ynh_validate_ip6 "$ipv6" || ipv6=''
|
ynh_validate_ip6 "$ipv6" || ipv6=''
|
||||||
interfaces="$(ip -j addr show | jq -r '[.[].ifname]|join(" ")')"
|
interfaces="$(ip -j addr show | jq -r '[.[].ifname]|join(" ")')"
|
||||||
wireless_interfaces="lo"
|
wireless_interfaces="lo"
|
||||||
|
@ -51,7 +51,8 @@ do_pre_regen() {
|
||||||
conf_files=$(ls -1 /etc/dnsmasq.d \
|
conf_files=$(ls -1 /etc/dnsmasq.d \
|
||||||
| awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }')
|
| awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }')
|
||||||
for domain in $conf_files; do
|
for domain in $conf_files; do
|
||||||
if [[ ! $YNH_DOMAINS =~ $domain ]] && [[ ! $domain =~ \.local$ ]]; then
|
if [[ ! $YNH_DOMAINS =~ $domain ]] && [[ ! $domain =~ \.local$ ]]
|
||||||
|
then
|
||||||
touch "${dnsmasq_dir}/${domain}"
|
touch "${dnsmasq_dir}/${domain}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -61,8 +62,7 @@ do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
# Force permission (to cover some edge cases where root's umask is like 027 and then dnsmasq cant read this file)
|
# Force permission (to cover some edge cases where root's umask is like 027 and then dnsmasq cant read this file)
|
||||||
chown root /etc/resolv.dnsmasq.conf
|
chown 644 /etc/resolv.dnsmasq.conf
|
||||||
chmod 644 /etc/resolv.dnsmasq.conf
|
|
||||||
|
|
||||||
# Fuck it, those domain/search entries from dhclient are usually annoying
|
# Fuck it, those domain/search entries from dhclient are usually annoying
|
||||||
# lying shit from the ISP trying to MiTM
|
# lying shit from the ISP trying to MiTM
|
||||||
|
@ -73,7 +73,7 @@ do_post_regen() {
|
||||||
|
|
||||||
grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >>/etc/dhcp/dhclient.conf
|
grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >>/etc/dhcp/dhclient.conf
|
||||||
grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >>/etc/dhcp/dhclient.conf
|
grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >>/etc/dhcp/dhclient.conf
|
||||||
grep -q '^supersede search "";' /etc/dhcp/dhclient.conf 2> /dev/null || echo 'supersede search "";' >> /etc/dhcp/dhclient.conf
|
grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >>/etc/dhcp/dhclient.conf
|
||||||
systemctl restart resolvconf
|
systemctl restart resolvconf
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -10,7 +10,7 @@ do_init_regen() {
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/nsswitch
|
cd /usr/share/yunohost/templates/nsswitch
|
||||||
|
|
||||||
install -D -m 644 nsswitch.conf "${pending_dir}/etc/nsswitch.conf"
|
install -D -m 644 nsswitch.conf "${pending_dir}/etc/nsswitch.conf"
|
||||||
}
|
}
|
|
@ -7,28 +7,22 @@ set -e
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
pending_dir=$1
|
pending_dir=$1
|
||||||
|
|
||||||
cd /usr/share/yunohost/conf/fail2ban
|
cd /usr/share/yunohost/templates/fail2ban
|
||||||
|
|
||||||
fail2ban_dir="${pending_dir}/etc/fail2ban"
|
fail2ban_dir="${pending_dir}/etc/fail2ban"
|
||||||
mkdir -p "${fail2ban_dir}/filter.d"
|
mkdir -p "${fail2ban_dir}/filter.d"
|
||||||
mkdir -p "${fail2ban_dir}/jail.d"
|
mkdir -p "${fail2ban_dir}/jail.d"
|
||||||
|
|
||||||
cp yunohost.conf "${fail2ban_dir}/filter.d/yunohost.conf"
|
cp yunohost.conf "${fail2ban_dir}/filter.d/yunohost.conf"
|
||||||
cp postfix-sasl.conf "${fail2ban_dir}/filter.d/postfix-sasl.conf"
|
|
||||||
cp jail.conf "${fail2ban_dir}/jail.conf"
|
cp jail.conf "${fail2ban_dir}/jail.conf"
|
||||||
|
|
||||||
export ssh_port="$(yunohost settings get 'security.ssh.ssh_port')"
|
export ssh_port="$(yunohost settings get 'security.ssh.port')"
|
||||||
ynh_render_template "yunohost-jails.conf" "${fail2ban_dir}/jail.d/yunohost-jails.conf"
|
ynh_render_template "yunohost-jails.conf" "${fail2ban_dir}/jail.d/yunohost-jails.conf"
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
if ls -l /etc/fail2ban/jail.d/*.conf; then
|
|
||||||
chown root:root /etc/fail2ban/jail.d/*.conf
|
|
||||||
chmod 644 /etc/fail2ban/jail.d/*.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ -z "$regen_conf_files" ]] \
|
[[ -z "$regen_conf_files" ]] \
|
||||||
|| systemctl reload fail2ban
|
|| systemctl reload fail2ban
|
||||||
}
|
}
|
|
@ -1,51 +1,32 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from moulinette.utils import log
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.filesystem import read_file, read_json, write_to_json
|
from moulinette.utils.filesystem import read_file, read_json, write_to_json
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.utils.system import (
|
from yunohost.utils.packages import ynh_packages_version
|
||||||
ynh_packages_version,
|
|
||||||
system_virt,
|
|
||||||
system_arch,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.diagnosis")
|
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class BaseSystemDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
virt = system_virt()
|
|
||||||
|
# Detect virt technology (if not bare metal) and arch
|
||||||
|
# Gotta have this "|| true" because it systemd-detect-virt return 'none'
|
||||||
|
# with an error code on bare metal ~.~
|
||||||
|
virt = check_output("systemd-detect-virt || true", shell=True)
|
||||||
if virt.lower() == "none":
|
if virt.lower() == "none":
|
||||||
virt = "bare-metal"
|
virt = "bare-metal"
|
||||||
|
|
||||||
# Detect arch
|
# Detect arch
|
||||||
arch = system_arch()
|
arch = check_output("dpkg --print-architecture")
|
||||||
hardware = dict(
|
hardware = dict(
|
||||||
meta={"test": "hardware"},
|
meta={"test": "hardware"},
|
||||||
status="INFO",
|
status="INFO",
|
||||||
|
@ -118,11 +99,9 @@ class MyDiagnoser(Diagnoser):
|
||||||
"repo": ynh_packages["yunohost"]["repo"],
|
"repo": ynh_packages["yunohost"]["repo"],
|
||||||
},
|
},
|
||||||
status="INFO" if consistent_versions else "ERROR",
|
status="INFO" if consistent_versions else "ERROR",
|
||||||
summary=(
|
summary="diagnosis_basesystem_ynh_main_version"
|
||||||
"diagnosis_basesystem_ynh_main_version"
|
|
||||||
if consistent_versions
|
if consistent_versions
|
||||||
else "diagnosis_basesystem_ynh_inconsistent_versions"
|
else "diagnosis_basesystem_ynh_inconsistent_versions",
|
||||||
),
|
|
||||||
details=ynh_version_details,
|
details=ynh_version_details,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -154,37 +133,6 @@ class MyDiagnoser(Diagnoser):
|
||||||
summary="diagnosis_backports_in_sources_list",
|
summary="diagnosis_backports_in_sources_list",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Using yunohost testing channel
|
|
||||||
if (
|
|
||||||
os.system(
|
|
||||||
"grep -q '^\\s*deb\\s*.*yunohost.org.*\\stesting' /etc/apt/sources.list /etc/apt/sources.list.d/*"
|
|
||||||
)
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
yield dict(
|
|
||||||
meta={"test": "apt_yunohost_channel"},
|
|
||||||
status="WARNING",
|
|
||||||
summary="diagnosis_using_yunohost_testing",
|
|
||||||
details=["diagnosis_using_yunohost_testing_details"],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Apt being mapped to 'stable' (instead of 'buster/bullseye/bookworm/trixie/...')
|
|
||||||
# will cause the machine to spontaenously upgrade everything as soon as next debian is released ...
|
|
||||||
# Note that we grep this from the policy for libc6, because it's hard to know exactly which apt repo
|
|
||||||
# is configured (it may not be simply debian.org)
|
|
||||||
if (
|
|
||||||
os.system(
|
|
||||||
"apt policy libc6 2>/dev/null | grep '^\\s*500' | awk '{print $3}' | tr '/' ' ' | awk '{print $1}' | grep -q 'stable'"
|
|
||||||
)
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
yield dict(
|
|
||||||
meta={"test": "apt_debian_codename"},
|
|
||||||
status="WARNING",
|
|
||||||
summary="diagnosis_using_stable_codename",
|
|
||||||
details=["diagnosis_using_stable_codename_details"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.number_of_recent_auth_failure() > 750:
|
if self.number_of_recent_auth_failure() > 750:
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "high_number_auth_failure"},
|
meta={"test": "high_number_auth_failure"},
|
||||||
|
@ -192,17 +140,8 @@ class MyDiagnoser(Diagnoser):
|
||||||
summary="diagnosis_high_number_auth_failures",
|
summary="diagnosis_high_number_auth_failures",
|
||||||
)
|
)
|
||||||
|
|
||||||
rfkill_wifi = self.rfkill_wifi()
|
|
||||||
if len(rfkill_wifi) > 0:
|
|
||||||
yield dict(
|
|
||||||
meta={"test": "rfkill_wifi"},
|
|
||||||
status="ERROR",
|
|
||||||
summary="diagnosis_rfkill_wifi",
|
|
||||||
details=["diagnosis_rfkill_wifi_details"],
|
|
||||||
data={"rfkill_wifi_error": rfkill_wifi},
|
|
||||||
)
|
|
||||||
|
|
||||||
def bad_sury_packages(self):
|
def bad_sury_packages(self):
|
||||||
|
|
||||||
packages_to_check = ["openssl", "libssl1.1", "libssl-dev"]
|
packages_to_check = ["openssl", "libssl1.1", "libssl-dev"]
|
||||||
for package in packages_to_check:
|
for package in packages_to_check:
|
||||||
cmd = "dpkg --list | grep '^ii' | grep gbp | grep -q -w %s" % package
|
cmd = "dpkg --list | grep '^ii' | grep gbp | grep -q -w %s" % package
|
||||||
|
@ -218,10 +157,12 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield (package, version_to_downgrade_to)
|
yield (package, version_to_downgrade_to)
|
||||||
|
|
||||||
def backports_in_sources_list(self):
|
def backports_in_sources_list(self):
|
||||||
|
|
||||||
cmd = "grep -q -nr '^ *deb .*-backports' /etc/apt/sources.list*"
|
cmd = "grep -q -nr '^ *deb .*-backports' /etc/apt/sources.list*"
|
||||||
return os.system(cmd) == 0
|
return os.system(cmd) == 0
|
||||||
|
|
||||||
def number_of_recent_auth_failure(self):
|
def number_of_recent_auth_failure(self):
|
||||||
|
|
||||||
# Those syslog facilities correspond to auth and authpriv
|
# Those syslog facilities correspond to auth and authpriv
|
||||||
# c.f. https://unix.stackexchange.com/a/401398
|
# c.f. https://unix.stackexchange.com/a/401398
|
||||||
# and https://wiki.archlinux.org/title/Systemd/Journal#Facility
|
# and https://wiki.archlinux.org/title/Systemd/Journal#Facility
|
||||||
|
@ -231,7 +172,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
try:
|
try:
|
||||||
return int(n_failures)
|
return int(n_failures)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(
|
self.logger_warning(
|
||||||
"Failed to parse number of recent auth failures, expected an int, got '%s'"
|
"Failed to parse number of recent auth failures, expected an int, got '%s'"
|
||||||
% n_failures
|
% n_failures
|
||||||
)
|
)
|
||||||
|
@ -255,20 +196,20 @@ class MyDiagnoser(Diagnoser):
|
||||||
if not os.path.exists(dpkg_log) or os.path.getmtime(
|
if not os.path.exists(dpkg_log) or os.path.getmtime(
|
||||||
cache_file
|
cache_file
|
||||||
) > os.path.getmtime(dpkg_log):
|
) > os.path.getmtime(dpkg_log):
|
||||||
logger.debug(
|
self.logger_debug(
|
||||||
"Using cached results for meltdown checker, from %s" % cache_file
|
"Using cached results for meltdown checker, from %s" % cache_file
|
||||||
)
|
)
|
||||||
return read_json(cache_file)[0]["VULNERABLE"]
|
return read_json(cache_file)[0]["VULNERABLE"]
|
||||||
|
|
||||||
# script taken from https://github.com/speed47/spectre-meltdown-checker
|
# script taken from https://github.com/speed47/spectre-meltdown-checker
|
||||||
# script commit id is store directly in the script
|
# script commit id is store directly in the script
|
||||||
SCRIPT_PATH = "/usr/lib/python3/dist-packages/yunohost/vendor/spectre-meltdown-checker/spectre-meltdown-checker.sh"
|
SCRIPT_PATH = "/usr/lib/moulinette/yunohost/vendor/spectre-meltdown-checker/spectre-meltdown-checker.sh"
|
||||||
|
|
||||||
# '--variant 3' corresponds to Meltdown
|
# '--variant 3' corresponds to Meltdown
|
||||||
# example output from the script:
|
# example output from the script:
|
||||||
# [{"NAME":"MELTDOWN","CVE":"CVE-2017-5754","VULNERABLE":false,"INFOS":"PTI mitigates the vulnerability"}]
|
# [{"NAME":"MELTDOWN","CVE":"CVE-2017-5754","VULNERABLE":false,"INFOS":"PTI mitigates the vulnerability"}]
|
||||||
try:
|
try:
|
||||||
logger.debug("Running meltdown vulnerability checker")
|
self.logger_debug("Running meltdown vulnerability checker")
|
||||||
call = subprocess.Popen(
|
call = subprocess.Popen(
|
||||||
"bash %s --batch json --variant 3" % SCRIPT_PATH,
|
"bash %s --batch json --variant 3" % SCRIPT_PATH,
|
||||||
shell=True,
|
shell=True,
|
||||||
|
@ -290,7 +231,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
# stuff which should be the last line
|
# stuff which should be the last line
|
||||||
output = output.strip()
|
output = output.strip()
|
||||||
if "\n" in output:
|
if "\n" in output:
|
||||||
logger.debug("Original meltdown checker output : %s" % output)
|
self.logger_debug("Original meltdown checker output : %s" % output)
|
||||||
output = output.split("\n")[-1]
|
output = output.split("\n")[-1]
|
||||||
|
|
||||||
CVEs = json.loads(output)
|
CVEs = json.loads(output)
|
||||||
|
@ -300,21 +241,18 @@ class MyDiagnoser(Diagnoser):
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
logger.warning(
|
self.logger_warning(
|
||||||
"Something wrong happened when trying to diagnose Meltdown vunerability, exception: %s"
|
"Something wrong happened when trying to diagnose Meltdown vunerability, exception: %s"
|
||||||
% e
|
% e
|
||||||
)
|
)
|
||||||
raise Exception("Command output for failed meltdown check: '%s'" % output)
|
raise Exception("Command output for failed meltdown check: '%s'" % output)
|
||||||
|
|
||||||
logger.debug(
|
self.logger_debug(
|
||||||
"Writing results from meltdown checker to cache file, %s" % cache_file
|
"Writing results from meltdown checker to cache file, %s" % cache_file
|
||||||
)
|
)
|
||||||
write_to_json(cache_file, CVEs)
|
write_to_json(cache_file, CVEs)
|
||||||
return CVEs[0]["VULNERABLE"]
|
return CVEs[0]["VULNERABLE"]
|
||||||
|
|
||||||
def rfkill_wifi(self):
|
|
||||||
if os.path.isfile("/etc/profile.d/wifi-check.sh"):
|
def main(args, env, loggers):
|
||||||
cmd = "bash /etc/profile.d/wifi-check.sh"
|
return BaseSystemDiagnoser(args, env, loggers).diagnose()
|
||||||
return check_output(cmd)
|
|
||||||
else:
|
|
||||||
return ""
|
|
|
@ -1,44 +1,25 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from moulinette.utils import log
|
|
||||||
from moulinette.utils.network import download_text
|
from moulinette.utils.network import download_text
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.utils.network import get_network_interfaces
|
from yunohost.utils.network import get_network_interfaces
|
||||||
from yunohost.settings import settings_get
|
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.diagnosis")
|
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class IPDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
# ############################################################ #
|
# ############################################################ #
|
||||||
# PING : Check that we can ping outside at least in ipv4 or v6 #
|
# PING : Check that we can ping outside at least in ipv4 or v6 #
|
||||||
# ############################################################ #
|
# ############################################################ #
|
||||||
|
@ -73,11 +54,9 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "dnsresolv"},
|
meta={"test": "dnsresolv"},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=(
|
summary="diagnosis_ip_broken_dnsresolution"
|
||||||
"diagnosis_ip_broken_dnsresolution"
|
|
||||||
if good_resolvconf
|
if good_resolvconf
|
||||||
else "diagnosis_ip_broken_resolvconf"
|
else "diagnosis_ip_broken_resolvconf",
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
# Otherwise, if the resolv conf is bad but we were able to resolve domain name,
|
# Otherwise, if the resolv conf is bad but we were able to resolve domain name,
|
||||||
|
@ -119,15 +98,10 @@ class MyDiagnoser(Diagnoser):
|
||||||
else:
|
else:
|
||||||
return local_ip
|
return local_ip
|
||||||
|
|
||||||
def is_ipvx_important(x):
|
|
||||||
return settings_get("misc.network.dns_exposure") in ["both", "ipv" + str(x)]
|
|
||||||
|
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "ipv4"},
|
meta={"test": "ipv4"},
|
||||||
data={"global": ipv4, "local": get_local_ip("ipv4")},
|
data={"global": ipv4, "local": get_local_ip("ipv4")},
|
||||||
status=(
|
status="SUCCESS" if ipv4 else "ERROR",
|
||||||
"SUCCESS" if ipv4 else "ERROR" if is_ipvx_important(4) else "WARNING"
|
|
||||||
),
|
|
||||||
summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4",
|
summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4",
|
||||||
details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None,
|
details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None,
|
||||||
)
|
)
|
||||||
|
@ -135,32 +109,17 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "ipv6"},
|
meta={"test": "ipv6"},
|
||||||
data={"global": ipv6, "local": get_local_ip("ipv6")},
|
data={"global": ipv6, "local": get_local_ip("ipv6")},
|
||||||
status=(
|
status="SUCCESS" if ipv6 else "WARNING",
|
||||||
"SUCCESS"
|
|
||||||
if ipv6
|
|
||||||
else (
|
|
||||||
"ERROR"
|
|
||||||
if settings_get("misc.network.dns_exposure") == "ipv6"
|
|
||||||
else "WARNING"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6",
|
summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6",
|
||||||
details=(
|
details=["diagnosis_ip_global", "diagnosis_ip_local"]
|
||||||
["diagnosis_ip_global", "diagnosis_ip_local"]
|
|
||||||
if ipv6
|
if ipv6
|
||||||
else [
|
else ["diagnosis_ip_no_ipv6_tip"],
|
||||||
(
|
|
||||||
"diagnosis_ip_no_ipv6_tip_important"
|
|
||||||
if is_ipvx_important(6)
|
|
||||||
else "diagnosis_ip_no_ipv6_tip"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO / FIXME : add some attempt to detect ISP (using whois ?) ?
|
# TODO / FIXME : add some attempt to detect ISP (using whois ?) ?
|
||||||
|
|
||||||
def can_ping_outside(self, protocol=4):
|
def can_ping_outside(self, protocol=4):
|
||||||
|
|
||||||
assert protocol in [
|
assert protocol in [
|
||||||
4,
|
4,
|
||||||
6,
|
6,
|
||||||
|
@ -185,14 +144,16 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
|
|
||||||
if not any(is_default_route(r) for r in routes):
|
if not any(is_default_route(r) for r in routes):
|
||||||
logger.debug(
|
self.logger_debug(
|
||||||
"No default route for IPv%s, so assuming there's no IP address for that version"
|
"No default route for IPv%s, so assuming there's no IP address for that version"
|
||||||
% protocol
|
% protocol
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping
|
# We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping
|
||||||
resolver_file = "/usr/share/yunohost/conf/dnsmasq/plain/resolv.dnsmasq.conf"
|
resolver_file = (
|
||||||
|
"/usr/share/yunohost/templates/dnsmasq/plain/resolv.dnsmasq.conf"
|
||||||
|
)
|
||||||
resolvers = [
|
resolvers = [
|
||||||
r.split(" ")[1]
|
r.split(" ")[1]
|
||||||
for r in read_file(resolver_file).split("\n")
|
for r in read_file(resolver_file).split("\n")
|
||||||
|
@ -239,6 +200,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"]
|
return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"]
|
||||||
|
|
||||||
def get_public_ip(self, protocol=4):
|
def get_public_ip(self, protocol=4):
|
||||||
|
|
||||||
# FIXME - TODO : here we assume that DNS resolution for ip.yunohost.org is working
|
# FIXME - TODO : here we assume that DNS resolution for ip.yunohost.org is working
|
||||||
# but if we want to be able to diagnose DNS resolution issues independently from
|
# but if we want to be able to diagnose DNS resolution issues independently from
|
||||||
# internet connectivity, we gotta rely on fixed IPs first....
|
# internet connectivity, we gotta rely on fixed IPs first....
|
||||||
|
@ -257,5 +219,9 @@ class MyDiagnoser(Diagnoser):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
protocol = str(protocol)
|
protocol = str(protocol)
|
||||||
e = str(e)
|
e = str(e)
|
||||||
logger.debug(f"Could not get public IPv{protocol} : {e}")
|
self.logger_debug(f"Could not get public IPv{protocol} : {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return IPDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,28 +1,11 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import List
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from publicsuffix2 import PublicSuffixList
|
|
||||||
|
|
||||||
from moulinette.utils import log
|
from datetime import datetime, timedelta
|
||||||
|
from publicsuffix import PublicSuffixList
|
||||||
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
from yunohost.utils.dns import (
|
from yunohost.utils.dns import (
|
||||||
|
@ -33,26 +16,22 @@ from yunohost.utils.dns import (
|
||||||
)
|
)
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list, _get_maindomain
|
from yunohost.domain import domain_list, _get_maindomain
|
||||||
from yunohost.dns import (
|
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
|
||||||
_build_dns_conf,
|
|
||||||
_get_dns_zone_for_domain,
|
|
||||||
_get_relative_name_for_dns_zone,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.diagnosis")
|
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
main_domain = _get_maindomain()
|
main_domain = _get_maindomain()
|
||||||
|
|
||||||
major_domains = domain_list(exclude_subdomains=True)["domains"]
|
major_domains = domain_list(exclude_subdomains=True)["domains"]
|
||||||
for domain in major_domains:
|
for domain in major_domains:
|
||||||
logger.debug("Diagnosing DNS conf for %s" % domain)
|
self.logger_debug("Diagnosing DNS conf for %s" % domain)
|
||||||
|
|
||||||
for report in self.check_domain(
|
for report in self.check_domain(
|
||||||
domain,
|
domain,
|
||||||
|
@ -75,6 +54,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield report
|
yield report
|
||||||
|
|
||||||
def check_domain(self, domain, is_main_domain):
|
def check_domain(self, domain, is_main_domain):
|
||||||
|
|
||||||
if is_special_use_tld(domain):
|
if is_special_use_tld(domain):
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"domain": domain},
|
meta={"domain": domain},
|
||||||
|
@ -85,7 +65,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
return
|
return
|
||||||
|
|
||||||
base_dns_zone = _get_dns_zone_for_domain(domain)
|
base_dns_zone = _get_dns_zone_for_domain(domain)
|
||||||
basename = _get_relative_name_for_dns_zone(domain, base_dns_zone)
|
basename = domain.replace(base_dns_zone, "").rstrip(".") or "@"
|
||||||
|
|
||||||
expected_configuration = _build_dns_conf(
|
expected_configuration = _build_dns_conf(
|
||||||
domain, include_empty_AAAA_if_no_ipv6=True
|
domain, include_empty_AAAA_if_no_ipv6=True
|
||||||
|
@ -94,11 +74,13 @@ class MyDiagnoser(Diagnoser):
|
||||||
categories = ["basic", "mail", "xmpp", "extra"]
|
categories = ["basic", "mail", "xmpp", "extra"]
|
||||||
|
|
||||||
for category in categories:
|
for category in categories:
|
||||||
|
|
||||||
records = expected_configuration[category]
|
records = expected_configuration[category]
|
||||||
discrepancies = []
|
discrepancies = []
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
for r in records:
|
for r in records:
|
||||||
|
|
||||||
id_ = r["type"] + ":" + r["name"]
|
id_ = r["type"] + ":" + r["name"]
|
||||||
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
|
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
|
||||||
|
|
||||||
|
@ -116,7 +98,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
if r["value"] == "@":
|
if r["value"] == "@":
|
||||||
r["value"] = domain + "."
|
r["value"] = domain + "."
|
||||||
elif r["type"] == "CNAME":
|
elif r["type"] == "CNAME":
|
||||||
r["value"] = r["value"] # + f".{base_dns_zone}."
|
r["value"] = r["value"] + f".{base_dns_zone}."
|
||||||
|
|
||||||
if self.current_record_match_expected(r):
|
if self.current_record_match_expected(r):
|
||||||
results[id_] = "OK"
|
results[id_] = "OK"
|
||||||
|
@ -177,15 +159,12 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield output
|
yield output
|
||||||
|
|
||||||
def get_current_record(self, fqdn, type_):
|
def get_current_record(self, fqdn, type_):
|
||||||
|
|
||||||
success, answers = dig(fqdn, type_, resolvers="force_external")
|
success, answers = dig(fqdn, type_, resolvers="force_external")
|
||||||
|
|
||||||
if success != "ok":
|
if success != "ok":
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if type_ == "TXT" and isinstance(answers, list):
|
|
||||||
for part in answers:
|
|
||||||
if part.startswith('"v=spf1'):
|
|
||||||
return part
|
|
||||||
return answers[0] if len(answers) == 1 else answers
|
return answers[0] if len(answers) == 1 else answers
|
||||||
|
|
||||||
def current_record_match_expected(self, r):
|
def current_record_match_expected(self, r):
|
||||||
|
@ -215,24 +194,12 @@ class MyDiagnoser(Diagnoser):
|
||||||
for part in current
|
for part in current
|
||||||
if not part.startswith("ip4:") and not part.startswith("ip6:")
|
if not part.startswith("ip4:") and not part.startswith("ip6:")
|
||||||
}
|
}
|
||||||
if "v=DMARC1" in r["value"]:
|
|
||||||
for param in current:
|
|
||||||
if "=" not in param:
|
|
||||||
return False
|
|
||||||
key, value = param.split("=", 1)
|
|
||||||
if key == "p":
|
|
||||||
return value in ["none", "quarantine", "reject"]
|
|
||||||
return expected == current
|
return expected == current
|
||||||
elif r["type"] == "MX":
|
elif r["type"] == "MX":
|
||||||
# For MX, we want to ignore the priority
|
# For MX, we want to ignore the priority
|
||||||
expected = r["value"].split()[-1]
|
expected = r["value"].split()[-1]
|
||||||
current = r["current"].split()[-1]
|
current = r["current"].split()[-1]
|
||||||
return expected == current
|
return expected == current
|
||||||
elif r["type"] == "CAA":
|
|
||||||
# For CAA, check only the last item, ignore the 0 / 128 nightmare
|
|
||||||
expected = r["value"].split()[-1]
|
|
||||||
current = r["current"].split()[-1]
|
|
||||||
return expected == current
|
|
||||||
else:
|
else:
|
||||||
return r["current"] == r["value"]
|
return r["current"] == r["value"]
|
||||||
|
|
||||||
|
@ -257,7 +224,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.debug("Dyndns domain: %s" % (domain))
|
self.logger_debug("Dyndns domain: %s" % (domain))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
expire_in = expire_date - datetime.now()
|
expire_in = expire_date - datetime.now()
|
||||||
|
@ -293,9 +260,9 @@ class MyDiagnoser(Diagnoser):
|
||||||
yield dict(
|
yield dict(
|
||||||
meta=meta,
|
meta=meta,
|
||||||
data={},
|
data={},
|
||||||
status=(
|
status=alert_type.upper()
|
||||||
alert_type.upper() if alert_type != "not_found" else "WARNING"
|
if alert_type != "not_found"
|
||||||
),
|
else "WARNING",
|
||||||
summary="diagnosis_domain_expiration_" + alert_type,
|
summary="diagnosis_domain_expiration_" + alert_type,
|
||||||
details=details[alert_type],
|
details=details[alert_type],
|
||||||
)
|
)
|
||||||
|
@ -332,3 +299,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
return datetime.strptime(match.group(1), "%d-%b-%Y")
|
return datetime.strptime(match.group(1), "%d-%b-%Y")
|
||||||
|
|
||||||
return "expiration_not_found"
|
return "expiration_not_found"
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return DNSRecordsDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,35 +1,19 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.service import _get_services
|
from yunohost.service import _get_services
|
||||||
from yunohost.settings import settings_get
|
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class PortsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
# TODO: report a warning if port 53 or 5353 is exposed to the outside world...
|
# TODO: report a warning if port 53 or 5353 is exposed to the outside world...
|
||||||
|
|
||||||
# This dict is something like :
|
# This dict is something like :
|
||||||
|
@ -45,10 +29,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
|
|
||||||
ipversions = []
|
ipversions = []
|
||||||
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
||||||
if (
|
if ipv4.get("status") == "SUCCESS":
|
||||||
ipv4.get("status") == "SUCCESS"
|
|
||||||
or settings_get("misc.network.dns_exposure") != "ipv6"
|
|
||||||
):
|
|
||||||
ipversions.append(4)
|
ipversions.append(4)
|
||||||
|
|
||||||
# To be discussed: we could also make this check dependent on the
|
# To be discussed: we could also make this check dependent on the
|
||||||
|
@ -122,10 +103,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
for record in dnsrecords.get("items", [])
|
for record in dnsrecords.get("items", [])
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if failed == 4 or ipv6_is_important():
|
||||||
failed == 4
|
|
||||||
and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]
|
|
||||||
) or (failed == 6 and ipv6_is_important()):
|
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"port": port},
|
meta={"port": port},
|
||||||
data={
|
data={
|
||||||
|
@ -168,3 +146,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
"diagnosis_ports_forwarding_tip",
|
"diagnosis_ports_forwarding_tip",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return PortsDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,45 +1,30 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from moulinette.utils.filesystem import read_file, mkdir, rm
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list
|
from yunohost.domain import domain_list
|
||||||
from yunohost.utils.dns import is_special_use_tld
|
from yunohost.utils.dns import is_special_use_tld
|
||||||
from yunohost.settings import settings_get
|
|
||||||
|
|
||||||
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class WebDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
all_domains = domain_list()["domains"]
|
all_domains = domain_list()["domains"]
|
||||||
domains_to_check = []
|
domains_to_check = []
|
||||||
for domain in all_domains:
|
for domain in all_domains:
|
||||||
|
|
||||||
# If the diagnosis location ain't defined, can't do diagnosis,
|
# If the diagnosis location ain't defined, can't do diagnosis,
|
||||||
# probably because nginx conf manually modified...
|
# probably because nginx conf manually modified...
|
||||||
nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain
|
nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain
|
||||||
|
@ -60,9 +45,9 @@ class MyDiagnoser(Diagnoser):
|
||||||
domains_to_check.append(domain)
|
domains_to_check.append(domain)
|
||||||
|
|
||||||
self.nonce = "".join(random.choice("0123456789abcedf") for i in range(16))
|
self.nonce = "".join(random.choice("0123456789abcedf") for i in range(16))
|
||||||
rm("/var/www/.well-known/ynh-diagnosis/", recursive=True, force=True)
|
os.system("rm -rf /tmp/.well-known/ynh-diagnosis/")
|
||||||
mkdir("/var/www/.well-known/ynh-diagnosis/", parents=True, mode=0o0775)
|
os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/")
|
||||||
os.system("touch /var/www/.well-known/ynh-diagnosis/%s" % self.nonce)
|
os.system("touch /tmp/.well-known/ynh-diagnosis/%s" % self.nonce)
|
||||||
|
|
||||||
if not domains_to_check:
|
if not domains_to_check:
|
||||||
return
|
return
|
||||||
|
@ -74,9 +59,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
|
|
||||||
ipversions = []
|
ipversions = []
|
||||||
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
||||||
if ipv4.get("status") == "SUCCESS" and settings_get(
|
if ipv4.get("status") == "SUCCESS":
|
||||||
"misc.network.dns_exposure"
|
|
||||||
) in ["both", "ipv4"]:
|
|
||||||
ipversions.append(4)
|
ipversions.append(4)
|
||||||
|
|
||||||
# To be discussed: we could also make this check dependent on the
|
# To be discussed: we could also make this check dependent on the
|
||||||
|
@ -96,10 +79,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
# "curl --head the.global.ip" will simply timeout...
|
# "curl --head the.global.ip" will simply timeout...
|
||||||
if self.do_hairpinning_test:
|
if self.do_hairpinning_test:
|
||||||
global_ipv4 = ipv4.get("data", {}).get("global", None)
|
global_ipv4 = ipv4.get("data", {}).get("global", None)
|
||||||
if global_ipv4 and settings_get("misc.network.dns_exposure") in [
|
if global_ipv4:
|
||||||
"both",
|
|
||||||
"ipv4",
|
|
||||||
]:
|
|
||||||
try:
|
try:
|
||||||
requests.head("http://" + global_ipv4, timeout=5)
|
requests.head("http://" + global_ipv4, timeout=5)
|
||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
|
@ -116,6 +96,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_http(self, domains, ipversions):
|
def test_http(self, domains, ipversions):
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
for ipversion in ipversions:
|
for ipversion in ipversions:
|
||||||
try:
|
try:
|
||||||
|
@ -140,6 +121,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
return
|
return
|
||||||
|
|
||||||
for domain in domains:
|
for domain in domains:
|
||||||
|
|
||||||
# i18n: diagnosis_http_bad_status_code
|
# i18n: diagnosis_http_bad_status_code
|
||||||
# i18n: diagnosis_http_connection_error
|
# i18n: diagnosis_http_connection_error
|
||||||
# i18n: diagnosis_http_timeout
|
# i18n: diagnosis_http_timeout
|
||||||
|
@ -148,10 +130,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
if all(
|
if all(
|
||||||
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions
|
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions
|
||||||
):
|
):
|
||||||
if 4 in ipversions and settings_get("misc.network.dns_exposure") in [
|
if 4 in ipversions:
|
||||||
"both",
|
|
||||||
"ipv4",
|
|
||||||
]:
|
|
||||||
self.do_hairpinning_test = True
|
self.do_hairpinning_test = True
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"domain": domain},
|
meta={"domain": domain},
|
||||||
|
@ -189,9 +168,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
AAAA_status = dnsrecords.get("data", {}).get("AAAA:@")
|
AAAA_status = dnsrecords.get("data", {}).get("AAAA:@")
|
||||||
|
|
||||||
return AAAA_status in ["OK", "WRONG"] or settings_get(
|
return AAAA_status in ["OK", "WRONG"]
|
||||||
"misc.network.dns_exposure"
|
|
||||||
) in ["both", "ipv6"]
|
|
||||||
|
|
||||||
if failed == 4 or ipv6_is_important_for_this_domain():
|
if failed == 4 or ipv6_is_important_for_this_domain():
|
||||||
yield dict(
|
yield dict(
|
||||||
|
@ -221,3 +198,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
summary="diagnosis_http_partially_unreachable",
|
summary="diagnosis_http_partially_unreachable",
|
||||||
details=[detail.replace("error_http_check", "diagnosis_http")],
|
details=[detail.replace("error_http_check", "diagnosis_http")],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return WebDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,29 +1,11 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
import re
|
import re
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
|
|
||||||
from moulinette.utils import log
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.filesystem import read_yaml
|
from moulinette.utils.filesystem import read_yaml
|
||||||
|
|
||||||
|
@ -32,18 +14,18 @@ from yunohost.domain import _get_maindomain, domain_list
|
||||||
from yunohost.settings import settings_get
|
from yunohost.settings import settings_get
|
||||||
from yunohost.utils.dns import dig
|
from yunohost.utils.dns import dig
|
||||||
|
|
||||||
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/dnsbl_list.yml"
|
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml"
|
||||||
|
|
||||||
logger = log.getActionLogger("yunohost.diagnosis")
|
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class MailDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 600
|
cache_duration = 600
|
||||||
dependencies: List[str] = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.ehlo_domain = _get_maindomain().lower()
|
|
||||||
|
self.ehlo_domain = _get_maindomain()
|
||||||
self.mail_domains = domain_list()["domains"]
|
self.mail_domains = domain_list()["domains"]
|
||||||
self.ipversions, self.ips = self.get_ips_checked()
|
self.ipversions, self.ips = self.get_ips_checked()
|
||||||
|
|
||||||
|
@ -60,7 +42,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
"check_queue", # i18n: diagnosis_mail_queue_ok
|
"check_queue", # i18n: diagnosis_mail_queue_ok
|
||||||
]
|
]
|
||||||
for check in checks:
|
for check in checks:
|
||||||
logger.debug("Running " + check)
|
self.logger_debug("Running " + check)
|
||||||
reports = list(getattr(self, check)())
|
reports = list(getattr(self, check)())
|
||||||
for report in reports:
|
for report in reports:
|
||||||
yield report
|
yield report
|
||||||
|
@ -132,7 +114,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
summary=summary,
|
summary=summary,
|
||||||
details=[summary + "_details"],
|
details=[summary + "_details"],
|
||||||
)
|
)
|
||||||
elif r["helo"].lower() != self.ehlo_domain:
|
elif r["helo"] != self.ehlo_domain:
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"test": "mail_ehlo", "ipversion": ipversion},
|
meta={"test": "mail_ehlo", "ipversion": ipversion},
|
||||||
data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain},
|
data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain},
|
||||||
|
@ -185,7 +167,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
rdns_domain = ""
|
rdns_domain = ""
|
||||||
if len(value) > 0:
|
if len(value) > 0:
|
||||||
rdns_domain = value[0][:-1] if value[0].endswith(".") else value[0]
|
rdns_domain = value[0][:-1] if value[0].endswith(".") else value[0]
|
||||||
if rdns_domain.lower() != self.ehlo_domain:
|
if rdns_domain != self.ehlo_domain:
|
||||||
details = [
|
details = [
|
||||||
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details"
|
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details"
|
||||||
] + details
|
] + details
|
||||||
|
@ -194,7 +176,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
data={
|
data={
|
||||||
"ip": ip,
|
"ip": ip,
|
||||||
"ehlo_domain": self.ehlo_domain,
|
"ehlo_domain": self.ehlo_domain,
|
||||||
"rdns_domain": rdns_domain.lower(),
|
"rdns_domain": rdns_domain,
|
||||||
},
|
},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary="diagnosis_mail_fcrdns_different_from_ehlo_domain",
|
summary="diagnosis_mail_fcrdns_different_from_ehlo_domain",
|
||||||
|
@ -277,7 +259,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
data={"error": str(e)},
|
data={"error": str(e)},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary="diagnosis_mail_queue_unavailable",
|
summary="diagnosis_mail_queue_unavailable",
|
||||||
details=["diagnosis_mail_queue_unavailable_details"],
|
details="diagnosis_mail_queue_unavailable_details",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if pending_emails > 100:
|
if pending_emails > 100:
|
||||||
|
@ -299,17 +281,13 @@ class MyDiagnoser(Diagnoser):
|
||||||
outgoing_ipversions = []
|
outgoing_ipversions = []
|
||||||
outgoing_ips = []
|
outgoing_ips = []
|
||||||
ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {}
|
ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {}
|
||||||
if ipv4.get("status") == "SUCCESS" and settings_get(
|
if ipv4.get("status") == "SUCCESS":
|
||||||
"misc.network.dns_exposure"
|
|
||||||
) in ["both", "ipv4"]:
|
|
||||||
outgoing_ipversions.append(4)
|
outgoing_ipversions.append(4)
|
||||||
global_ipv4 = ipv4.get("data", {}).get("global", {})
|
global_ipv4 = ipv4.get("data", {}).get("global", {})
|
||||||
if global_ipv4:
|
if global_ipv4:
|
||||||
outgoing_ips.append(global_ipv4)
|
outgoing_ips.append(global_ipv4)
|
||||||
|
|
||||||
if settings_get("email.smtp.smtp_allow_ipv6") or settings_get(
|
if settings_get("smtp.allow_ipv6"):
|
||||||
"misc.network.dns_exposure"
|
|
||||||
) in ["both", "ipv6"]:
|
|
||||||
ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {}
|
ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {}
|
||||||
if ipv6.get("status") == "SUCCESS":
|
if ipv6.get("status") == "SUCCESS":
|
||||||
outgoing_ipversions.append(6)
|
outgoing_ipversions.append(6)
|
||||||
|
@ -317,3 +295,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
if global_ipv6:
|
if global_ipv6:
|
||||||
outgoing_ips.append(global_ipv6)
|
outgoing_ips.append(global_ipv6)
|
||||||
return (outgoing_ipversions, outgoing_ips)
|
return (outgoing_ipversions, outgoing_ips)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return MailDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,37 +1,23 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.service import service_status
|
from yunohost.service import service_status
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class ServicesDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 300
|
cache_duration = 300
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
all_result = service_status()
|
all_result = service_status()
|
||||||
|
|
||||||
for service, result in sorted(all_result.items()):
|
for service, result in sorted(all_result.items()):
|
||||||
|
|
||||||
item = dict(
|
item = dict(
|
||||||
meta={"service": service},
|
meta={"service": service},
|
||||||
data={
|
data={
|
||||||
|
@ -55,3 +41,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
item["summary"] = "diagnosis_services_running"
|
item["summary"] = "diagnosis_services_running"
|
||||||
|
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return ServicesDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,38 +1,22 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import psutil
|
import psutil
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class SystemResourcesDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 300
|
cache_duration = 300
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
MB = 1024 ** 2
|
MB = 1024 ** 2
|
||||||
GB = MB * 1024
|
GB = MB * 1024
|
||||||
|
|
||||||
|
@ -187,6 +171,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def analyzed_kern_log():
|
def analyzed_kern_log():
|
||||||
|
|
||||||
cmd = 'tail -n 10000 /var/log/kern.log | grep "oom_reaper: reaped process" || true'
|
cmd = 'tail -n 10000 /var/log/kern.log | grep "oom_reaper: reaped process" || true'
|
||||||
out = check_output(cmd)
|
out = check_output(cmd)
|
||||||
lines = out.split("\n") if out else []
|
lines = out.split("\n") if out else []
|
||||||
|
@ -231,3 +216,7 @@ def round_(n):
|
||||||
if n > 10:
|
if n > 10:
|
||||||
n = int(round(n))
|
n = int(round(n))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return SystemResourcesDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,24 +1,7 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from yunohost.settings import settings_get
|
from yunohost.settings import settings_get
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
|
@ -26,12 +9,14 @@ from yunohost.regenconf import _get_regenconf_infos, _calculate_hash
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class RegenconfDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 300
|
cache_duration = 300
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
regenconf_modified_files = list(self.manually_modified_files())
|
regenconf_modified_files = list(self.manually_modified_files())
|
||||||
|
|
||||||
if not regenconf_modified_files:
|
if not regenconf_modified_files:
|
||||||
|
@ -67,7 +52,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check consistency between actual ssh port in sshd_config vs. setting
|
# Check consistency between actual ssh port in sshd_config vs. setting
|
||||||
ssh_port_setting = settings_get("security.ssh.ssh_port")
|
ssh_port_setting = settings_get("security.ssh.port")
|
||||||
ssh_port_line = re.findall(
|
ssh_port_line = re.findall(
|
||||||
r"\bPort *([0-9]{2,5})\b", read_file("/etc/ssh/sshd_config")
|
r"\bPort *([0-9]{2,5})\b", read_file("/etc/ssh/sshd_config")
|
||||||
)
|
)
|
||||||
|
@ -80,7 +65,12 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
|
|
||||||
def manually_modified_files(self):
|
def manually_modified_files(self):
|
||||||
|
|
||||||
for category, infos in _get_regenconf_infos().items():
|
for category, infos in _get_regenconf_infos().items():
|
||||||
for path, hash_ in infos["conffiles"].items():
|
for path, hash_ in infos["conffiles"].items():
|
||||||
if hash_ != _calculate_hash(path):
|
if hash_ != _calculate_hash(path):
|
||||||
yield {"path": path, "category": category}
|
yield {"path": path, "category": category}
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return RegenconfDiagnoser(args, env, loggers).diagnose()
|
|
@ -1,35 +1,20 @@
|
||||||
#
|
#!/usr/bin/env python
|
||||||
# Copyright (c) 2024 YunoHost Contributors
|
|
||||||
#
|
|
||||||
# This file is part of YunoHost (see https://yunohost.org)
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from yunohost.app import app_list
|
from yunohost.app import app_list
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
|
|
||||||
|
|
||||||
class MyDiagnoser(Diagnoser):
|
class AppDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 300
|
cache_duration = 300
|
||||||
dependencies: List[str] = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
apps = app_list(full=True)["apps"]
|
apps = app_list(full=True)["apps"]
|
||||||
for app in apps:
|
for app in apps:
|
||||||
app["issues"] = list(self.issues(app))
|
app["issues"] = list(self.issues(app))
|
||||||
|
@ -42,6 +27,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for app in apps:
|
for app in apps:
|
||||||
|
|
||||||
if not app["issues"]:
|
if not app["issues"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -59,15 +45,16 @@ class MyDiagnoser(Diagnoser):
|
||||||
)
|
)
|
||||||
|
|
||||||
def issues(self, app):
|
def issues(self, app):
|
||||||
|
|
||||||
# Check quality level in catalog
|
# Check quality level in catalog
|
||||||
|
|
||||||
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":
|
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":
|
||||||
yield ("warning", "diagnosis_apps_not_in_app_catalog")
|
yield ("error", "diagnosis_apps_not_in_app_catalog")
|
||||||
elif (
|
elif (
|
||||||
not isinstance(app["from_catalog"].get("level"), int)
|
not isinstance(app["from_catalog"].get("level"), int)
|
||||||
or app["from_catalog"]["level"] == 0
|
or app["from_catalog"]["level"] == 0
|
||||||
):
|
):
|
||||||
yield ("warning", "diagnosis_apps_broken")
|
yield ("error", "diagnosis_apps_broken")
|
||||||
elif app["from_catalog"]["level"] <= 4:
|
elif app["from_catalog"]["level"] <= 4:
|
||||||
yield ("warning", "diagnosis_apps_bad_quality")
|
yield ("warning", "diagnosis_apps_bad_quality")
|
||||||
|
|
||||||
|
@ -76,9 +63,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
yunohost_version_req = (
|
yunohost_version_req = (
|
||||||
app["manifest"].get("requirements", {}).get("yunohost", "").strip(">= ")
|
app["manifest"].get("requirements", {}).get("yunohost", "").strip(">= ")
|
||||||
)
|
)
|
||||||
if yunohost_version_req.startswith("2.") or yunohost_version_req.startswith(
|
if yunohost_version_req.startswith("2."):
|
||||||
"3."
|
|
||||||
):
|
|
||||||
yield ("error", "diagnosis_apps_outdated_ynh_requirement")
|
yield ("error", "diagnosis_apps_outdated_ynh_requirement")
|
||||||
|
|
||||||
deprecated_helpers = [
|
deprecated_helpers = [
|
||||||
|
@ -105,3 +90,7 @@ class MyDiagnoser(Diagnoser):
|
||||||
== 0
|
== 0
|
||||||
):
|
):
|
||||||
yield ("error", "diagnosis_apps_deprecated_practices")
|
yield ("error", "diagnosis_apps_deprecated_practices")
|
||||||
|
|
||||||
|
|
||||||
|
def main(args, env, loggers):
|
||||||
|
return AppDiagnoser(args, env, loggers).diagnose()
|
|
@ -3,6 +3,6 @@ backup_dir="$1/conf/ynh"
|
||||||
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host
|
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host
|
||||||
cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml
|
cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml
|
||||||
[ ! -d "${backup_dir}/domains" ] || cp -a "${backup_dir}/domains" /etc/yunohost/domains
|
[ ! -d "${backup_dir}/domains" ] || cp -a "${backup_dir}/domains" /etc/yunohost/domains
|
||||||
[ ! -e "${backup_dir}/settings.yml" ] || cp -a "${backup_dir}/settings.yml" "/etc/yunohost/settings.yml"
|
[ ! -e "${backup_dir}/settings.json" ] || cp -a "${backup_dir}/settings.json" "/etc/yunohost/settings.json"
|
||||||
[ ! -d "${backup_dir}/dyndns" ] || cp -raT "${backup_dir}/dyndns" "/etc/yunohost/dyndns"
|
[ ! -d "${backup_dir}/dyndns" ] || cp -raT "${backup_dir}/dyndns" "/etc/yunohost/dyndns"
|
||||||
[ ! -d "${backup_dir}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim"
|
[ ! -d "${backup_dir}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue