Merge branch 'dev' into dev_on_muc

This commit is contained in:
Alexandre Aubin 2021-10-13 14:54:55 +02:00 committed by GitHub
commit e3d862dc15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
224 changed files with 20494 additions and 10956 deletions

2
.coveragerc Normal file
View file

@ -0,0 +1,2 @@
[report]
omit=src/yunohost/tests/*,src/yunohost/vendor/*,/usr/lib/moulinette/yunohost/*

View file

@ -1,9 +1,11 @@
---
stages: stages:
- build - build
- install - install
- tests - tests
- lint - lint
- doc - doc
- translation
default: default:
tags: tags:
@ -11,12 +13,18 @@ default:
# All jobs are interruptible by default # All jobs are interruptible by default
interruptible: true interruptible: true
# see: https://docs.gitlab.com/ee/ci/yaml/#switch-between-branch-pipelines-and-merge-request-pipelines
workflow:
rules:
- 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_COMMIT_TAG # For tags
- if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" # If it's not the default branch and if it's a push, then do not trigger a build
when: never
- when: always
variables: variables:
YNH_BUILD_DIR: "ynh-build" YNH_BUILD_DIR: "ynh-build"
include: include:
- local: .gitlab/ci/build.gitlab-ci.yml - local: .gitlab/ci/*.gitlab-ci.yml
- local: .gitlab/ci/install.gitlab-ci.yml
- local: .gitlab/ci/test.gitlab-ci.yml
- local: .gitlab/ci/lint.gitlab-ci.yml
- local: .gitlab/ci/doc.gitlab-ci.yml

View file

@ -12,9 +12,9 @@ generate-helpers-doc:
- git config --global user.name "$GITHUB_USER" - git config --global user.name "$GITHUB_USER"
script: script:
- cd doc - cd doc
- python generate_helper_doc.py - python3 generate_helper_doc.py
- 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.html doc_repo/packaging_apps_helpers.md - cp helpers.md doc_repo/pages/04.contribute/04.packaging_apps/11.helpers/packaging_apps_helpers.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}"
@ -22,6 +22,6 @@ generate-helpers-doc:
- 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 - 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.html - doc/helpers.md
only: only:
- tags - tags

View file

@ -3,6 +3,7 @@
######################################## ########################################
# 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"
---
lint37: lint37:
stage: lint stage: lint
image: "before-install" image: "before-install"
@ -18,6 +19,13 @@ invalidcode37:
script: script:
- tox -e py37-invalidcode - tox -e py37-invalidcode
mypy:
stage: lint
image: "before-install"
needs: []
script:
- tox -e py37-mypy
format-check: format-check:
stage: lint stage: lint
image: "before-install" image: "before-install"
@ -37,10 +45,12 @@ format-run:
- hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo - hub clone --branch ${CI_COMMIT_REF_NAME} "https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git" github_repo
- cd github_repo - cd github_repo
script: script:
# checkout or create and checkout the branch # create a local branch that will overwrite distant one
- hub checkout "ci-format-${CI_COMMIT_REF_NAME}" || hub checkout -b "ci-format-${CI_COMMIT_REF_NAME}" - git checkout -b "ci-format-${CI_COMMIT_REF_NAME}" --no-track
- tox -e py37-black-run - tox -e py37-black-run
- hub commit -am "[CI] Format code" || true - '[ $(git diff | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Format code" || true
- git push -f origin "ci-format-${CI_COMMIT_REF_NAME}":"ci-format-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Format code" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd - hub pull-request -m "[CI] Format code" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only: only:
refs: refs:

View file

@ -36,7 +36,9 @@ full-tests:
- *install_debs - *install_debs
- yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace - yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace
script: script:
- python3 -m pytest --cov=yunohost tests/ src/yunohost/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
@ -48,73 +50,159 @@ full-tests:
reports: reports:
junit: report.xml junit: report.xml
root-tests: test-i18n-keys:
extends: .test-stage extends: .test-stage
script: script:
- python3 -m pytest tests - 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:
extends: .test-stage
script:
- python3 -m pytest tests/test_actionmap.py
only:
changes:
- data/actionsmap/*.yml
test-helpers:
extends: .test-stage
script:
- cd tests
- bash test_helpers.sh
only:
changes:
- data/helpers.d/*
test-domains:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_domains.py
only:
changes:
- src/yunohost/domain.py
test-dns:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_dns.py
only:
changes:
- src/yunohost/dns.py
- src/yunohost/utils/dns.py
test-apps: test-apps:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_apps.py
- python3 -m pytest tests/test_apps.py only:
changes:
- src/yunohost/app.py
test-appscatalog: test-appscatalog:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_app_catalog.py
- python3 -m pytest tests/test_appscatalog.py only:
changes:
- src/yunohost/app_calalog.py
test-appurl: test-appurl:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_appurl.py
- python3 -m pytest tests/test_appurl.py only:
changes:
- src/yunohost/app.py
test-apps-arguments-parsing: test-questions:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_questions.py
- python3 -m pytest tests/test_apps_arguments_parsing.py only:
changes:
- src/yunohost/utils/config.py
test-backuprestore: test-app-config:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_app_config.py
- python3 -m pytest tests/test_backuprestore.py only:
changes:
- src/yunohost/app.py
- src/yunohost/utils/config.py
test-changeurl: test-changeurl:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_changeurl.py
- python3 -m pytest tests/test_changeurl.py only:
changes:
- src/yunohost/app.py
test-backuprestore:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_backuprestore.py
only:
changes:
- src/yunohost/backup.py
test-permission: test-permission:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_permission.py
- python3 -m pytest tests/test_permission.py only:
changes:
- src/yunohost/permission.py
test-settings: test-settings:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_settings.py
- python3 -m pytest tests/test_settings.py only:
changes:
- src/yunohost/settings.py
test-user-group: test-user-group:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_user-group.py
- python3 -m pytest tests/test_user-group.py only:
changes:
- src/yunohost/user.py
test-regenconf: test-regenconf:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_regenconf.py
- python3 -m pytest tests/test_regenconf.py only:
changes:
- src/yunohost/regenconf.py
test-service: test-service:
extends: .test-stage extends: .test-stage
script: script:
- cd src/yunohost - python3 -m pytest src/yunohost/tests/test_service.py
- python3 -m pytest tests/test_service.py only:
changes:
- src/yunohost/service.py
test-ldapauth:
extends: .test-stage
script:
- python3 -m pytest src/yunohost/tests/test_ldapauth.py
only:
changes:
- src/yunohost/authenticators/*.py

View file

@ -0,0 +1,29 @@
########################################
# TRANSLATION
########################################
autofix-translated-strings:
stage: translation
image: "before-install"
needs: []
before_script:
- apt-get update -y && apt-get install git hub -y
- git config --global user.email "yunohost@yunohost.org"
- git config --global user.name "$GITHUB_USER"
- git remote set-url origin https://$GITHUB_TOKEN:x-oauth-basic@github.com/YunoHost/yunohost.git
script:
- cd tests # Maybe move this script location to another folder?
# create a local branch that will overwrite distant one
- git checkout -b "ci-autofix-translated-strings-${CI_COMMIT_REF_NAME}" --no-track
- python3 remove_stale_translated_strings.py
- python3 autofix_locale_format.py
- 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 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:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only:
variables:
- $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
changes:
- locales/*

View file

@ -6,8 +6,10 @@
<div align="center"> <div align="center">
[![Build status](https://travis-ci.org/YunoHost/yunohost.svg?branch=stretch-unstable)](https://travis-ci.org/YunoHost/yunohost) ![Version](https://img.shields.io/github/v/tag/yunohost/yunohost?label=version&sort=semver)
[![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/stretch-unstable/LICENSE) [![Build status](https://shields.io/gitlab/pipeline/yunohost/yunohost/dev)](https://gitlab.com/yunohost/yunohost/-/pipelines)
![Test coverage](https://img.shields.io/gitlab/coverage/yunohost/yunohost/dev)
[![GitHub license](https://img.shields.io/github/license/YunoHost/yunohost)](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost) [![Mastodon Follow](https://img.shields.io/mastodon/follow/28084)](https://mastodon.social/@yunohost)
</div> </div>
@ -35,7 +37,7 @@ Webadmin ([Yunohost-Admin](https://github.com/YunoHost/yunohost-admin)) | Single
- 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 src="https://translate.yunohost.org/widgets/yunohost/-/multi-auto.svg" alt="Translation status" /> <img src="https://translate.yunohost.org/widgets/yunohost/-/core/horizontal-auto.svg" alt="Translation status" />
</p> </p>
## License ## License

170
bin/yunomdns Executable file
View file

@ -0,0 +1,170 @@
#!/usr/bin/env python3
"""
Pythonic declaration of mDNS .local domains for YunoHost
"""
import sys
import yaml
from time import sleep
from typing import List, Dict
import ifaddr
from ipaddress import ip_address
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
def get_network_local_interfaces() -> Dict[str, Dict[str, List[str]]]:
"""
Returns interfaces with their associated local IPs
"""
interfaces = {
adapter.name: {
"ipv4": [ip.ip for ip in adapter.ips if ip.is_IPv4 and ip_address(ip.ip).is_private],
"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()
if adapter.name != "lo"
}
return interfaces
# Listener class, to detect duplicates on the network
# Stores the list of servers in its list property
class Listener:
def __init__(self):
self.list = []
def remove_service(self, zeroconf, type, name):
info = zeroconf.get_service_info(type, name)
self.list.remove(info.server)
def update_service(self, zeroconf, type, name):
pass
def add_service(self, zeroconf, type, name):
info = zeroconf.get_service_info(type, name)
self.list.append(info.server[:-1])
def main() -> bool:
###
# CONFIG
###
with open("/etc/yunohost/mdns.yml", "r") as f:
config = yaml.safe_load(f) or {}
required_fields = ["domains"]
missing_fields = [field for field in required_fields if field not in config]
interfaces = get_network_local_interfaces()
if missing_fields:
print(f"The fields {missing_fields} are required in mdns.yml")
return False
if "interfaces" not in config:
config["interfaces"] = [interface
for interface, local_ips in interfaces.items()
if local_ips["ipv4"]]
if "ban_interfaces" in config:
config["interfaces"] = [interface
for interface in config["interfaces"]
if interface not in config["ban_interfaces"]]
# Let's discover currently published .local domains accross the network
zc = Zeroconf()
listener = Listener()
browser = ServiceBrowser(zc, "_device-info._tcp.local.", listener)
sleep(2)
browser.cancel()
zc.close()
# Always attempt to publish yunohost.local
if "yunohost.local" not in config["domains"]:
config["domains"].append("yunohost.local")
def find_domain_not_already_published(domain):
# Try domain.local ... but if it's already published by another entity,
# try domain-2.local, domain-3.local, ...
i = 1
domain_i = domain
while domain_i in listener.list:
print(f"Uh oh, {domain_i} already exists on the network...")
i += 1
domain_i = domain.replace(".local", f"-{i}.local")
return domain_i
config['domains'] = [find_domain_not_already_published(domain) for domain in config['domains']]
zcs: Dict[Zeroconf, List[ServiceInfo]] = {}
for interface in config["interfaces"]:
if interface not in interfaces:
print(f"Interface {interface} listed in config file is not present on system.")
continue
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
# Buster only ships 0.1.6
# Bullseye ships 0.1.7
# To be re-enabled once we're on bullseye...
# ips: List[str] = interfaces[interface]["ipv4"] + interfaces[interface]["ipv6"]
ips: List[str] = interfaces[interface]["ipv4"]
# If at least one IP is listed
if not ips:
continue
# Create a Zeroconf object, and store the ServiceInfos
zc = Zeroconf(interfaces=ips) # type: ignore
zcs[zc] = []
for d in config["domains"]:
d_domain = d.replace(".local", "")
if "." in d_domain:
print(f"{d_domain}.local: subdomains are not supported.")
continue
# Create a ServiceInfo object for each .local domain
zcs[zc].append(
ServiceInfo(
type_="_device-info._tcp.local.",
name=f"{interface}: {d_domain}._device-info._tcp.local.",
parsed_addresses=ips,
port=80,
server=f"{d}.",
)
)
print(f"Adding {d} with addresses {ips} on interface {interface}")
# Run registration
print("Registering...")
for zc, infos in zcs.items():
for info in infos:
zc.register_service(info, allow_name_change=True, cooperating_responders=True)
try:
print("Registered. Press Ctrl+C or stop service to stop.")
while True:
sleep(1)
except KeyboardInterrupt:
pass
finally:
print("Unregistering...")
for zc, infos in zcs.items():
zc.unregister_all_services()
zc.close()
return True
if __name__ == "__main__":
sys.exit(0 if main() else 1)

View file

@ -34,7 +34,7 @@ Haste server.
For example, to paste the output of the YunoHost diagnosis, you For example, to paste the output of the YunoHost diagnosis, you
can simply execute the following: can simply execute the following:
yunohost tools diagnosis | ${0} yunohost diagnosis show | ${0}
It will return the URL where you can access the pasted data. It will return the URL where you can access the pasted data.

View file

@ -66,19 +66,19 @@ then
echo "$LOGO_AND_FINGERPRINTS" echo "$LOGO_AND_FINGERPRINTS"
cat << EOF cat << EOF
=============================================================================== ===============================================================================
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 administration password. - 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}
- or in this terminal by answering 'yes' to the following question - or in this terminal by answering 'yes' to the following question
If this is your first time with YunoHost, it is strongly recommended to take If this is your first time with YunoHost, it is strongly recommended to take
time to read the administator documentation and in particular the sections time to read the administator documentation and in particular the sections
'Finalizing your setup' and 'Getting to know YunoHost'. It is available at 'Finalizing your setup' and 'Getting to know YunoHost'. It is available at
the following URL : https://yunohost.org/admindoc the following URL: https://yunohost.org/admindoc
=============================================================================== ===============================================================================
EOF EOF

View file

@ -33,18 +33,10 @@
# Global parameters # # Global parameters #
############################# #############################
_global: _global:
configuration: name: yunohost.admin
authenticate: authentication:
- api api: ldap_admin
authenticator: cli: null
default:
vendor: ldap
help: admin_password
parameters:
uri: ldap://localhost:389
base_dn: dc=yunohost,dc=org
user_rdn: cn=admin,dc=yunohost,dc=org
argument_auth: false
arguments: arguments:
-v: -v:
full: --version full: --version
@ -67,7 +59,7 @@ user:
api: GET /users api: GET /users
arguments: arguments:
--fields: --fields:
help: fields to fetch help: fields to fetch (username, fullname, mail, mail-alias, mail-forward, mailbox-quota, groups, shell, home-path)
nargs: "+" nargs: "+"
### user_create() ### user_create()
@ -207,6 +199,28 @@ user:
username: username:
help: Username or email to get information help: Username or email to get information
### user_export()
export:
action_help: Export users into CSV
api: GET /users/export
### user_import()
import:
action_help: Import several users from CSV
api: POST /users/import
arguments:
csvfile:
help: "CSV file with columns username, firstname, lastname, password, mail, mailbox-quota, mail-alias, mail-forward, groups (separated by coma)"
type: open
-u:
full: --update
help: Update all existing users contained in the CSV file (by default existing users are ignored)
action: store_true
-d:
full: --delete
help: Delete all existing users that are not contained in the CSV file (by default existing users are kept)
action: store_true
subcategories: subcategories:
group: group:
subcategory_help: Manage user groups subcategory_help: Manage user groups
@ -252,30 +266,6 @@ user:
extra: extra:
pattern: *pattern_groupname pattern: *pattern_groupname
### user_group_update()
update:
action_help: Update group
api: PUT /users/groups/<groupname>
arguments:
groupname:
help: Name of the group to be updated
extra:
pattern: *pattern_groupname
-a:
full: --add
help: User(s) to add in the group
nargs: "*"
metavar: USERNAME
extra:
pattern: *pattern_username
-r:
full: --remove
help: User(s) to remove in the group
nargs: "*"
metavar: USERNAME
extra:
pattern: *pattern_username
### user_group_info() ### user_group_info()
info: info:
action_help: Get information about a specific group action_help: Get information about a specific group
@ -286,6 +276,38 @@ user:
extra: extra:
pattern: *pattern_username pattern: *pattern_username
### user_group_add()
add:
action_help: Add users to group
api: PUT /users/groups/<groupname>/add/<usernames>
arguments:
groupname:
help: Name of the group to add user(s) to
extra:
pattern: *pattern_groupname
usernames:
help: User(s) to add in the group
nargs: "*"
metavar: USERNAME
extra:
pattern: *pattern_username
### user_group_remove()
remove:
action_help: Remove users from group
api: PUT /users/groups/<groupname>/remove/<usernames>
arguments:
groupname:
help: Name of the group to remove user(s) from
extra:
pattern: *pattern_groupname
usernames:
help: User(s) to remove from the group
nargs: "*"
metavar: USERNAME
extra:
pattern: *pattern_username
permission: permission:
subcategory_help: Manage permissions subcategory_help: Manage permissions
actions: actions:
@ -295,6 +317,9 @@ user:
action_help: List permissions and corresponding accesses action_help: List permissions and corresponding accesses
api: GET /users/permissions api: GET /users/permissions
arguments: arguments:
apps:
help: Apps to list permission for (all by default)
nargs: "*"
-s: -s:
full: --short full: --short
help: Only list permission names help: Only list permission names
@ -319,20 +344,6 @@ user:
arguments: arguments:
permission: permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions) help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions)
-a:
full: --add
help: Group or usernames to grant this permission to
nargs: "*"
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
-r:
full: --remove
help: Group or usernames revoke this permission from
nargs: "*"
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
-l: -l:
full: --label full: --label
help: Label for this permission. This label will be shown on the SSO and in the admin help: Label for this permission. This label will be shown on the SSO and in the admin
@ -343,10 +354,38 @@ user:
- 'True' - 'True'
- 'False' - 'False'
## user_permission_add()
add:
action_help: Grant permission to group or user
api: PUT /users/permissions/<permission>/add/<names>
arguments:
permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions)
names:
help: Group or usernames to grant this permission to
nargs: "*"
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
## user_permission_remove()
remove:
action_help: Revoke permission to group or user
api: PUT /users/permissions/<permission>/remove/<names>
arguments:
permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions)
names:
help: Group or usernames to revoke this permission to
nargs: "*"
metavar: GROUP_OR_USER
extra:
pattern: *pattern_username
## user_permission_reset() ## user_permission_reset()
reset: reset:
action_help: Reset allowed groups to the default (all_users) for a given permission action_help: Reset allowed groups to the default (all_users) for a given permission
api: DELETE /users/permissions/<app> api: DELETE /users/permissions/<permission>
arguments: arguments:
permission: permission:
help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions) help: Permission to manage (e.g. mail or nextcloud or wordpress.editors) (use "yunohost user permission list" and "yunohost user permission -f" to see all the current permissions)
@ -354,25 +393,6 @@ user:
ssh: ssh:
subcategory_help: Manage ssh access subcategory_help: Manage ssh access
actions: actions:
### user_ssh_enable()
allow:
action_help: Allow the user to uses ssh
api: POST /users/ssh/enable
arguments:
username:
help: Username of the user
extra:
pattern: *pattern_username
### user_ssh_disable()
disallow:
action_help: Disallow the user to uses ssh
api: POST /users/ssh/disable
arguments:
username:
help: Username of the user
extra:
pattern: *pattern_username
### user_ssh_keys_list() ### user_ssh_keys_list()
list-keys: list-keys:
@ -397,7 +417,7 @@ user:
help: The key to be added help: The key to be added
-c: -c:
full: --comment full: --comment
help: Optionnal comment about the key help: Optional comment about the key
### user_ssh_keys_remove() ### user_ssh_keys_remove()
remove-key: remove-key:
@ -411,7 +431,6 @@ user:
key: key:
help: The key to be removed help: The key to be removed
############################# #############################
# Domain # # Domain #
############################# #############################
@ -451,21 +470,25 @@ domain:
help: Domain to delete help: Domain to delete
extra: extra:
pattern: *pattern_domain pattern: *pattern_domain
-r:
full: --remove-apps
help: Remove apps installed on the domain
action: store_true
-f:
full: --force
help: Do not ask confirmation to remove apps
action: store_true
### domain_dns_conf() ### domain_dns_conf()
dns-conf: dns-conf:
deprecated: true
action_help: Generate sample DNS configuration for a domain action_help: Generate sample DNS configuration for a domain
api: GET /domains/<domain>/dns
arguments: arguments:
domain: domain:
help: Target domain help: Target domain
-t:
full: --ttl
help: Time To Live (TTL) in second before DNS servers update. Default is 3600 seconds (i.e. 1 hour).
extra: extra:
pattern: pattern: *pattern_domain
- !!str ^[0-9]+$
- "pattern_positive_number"
### domain_maindomain() ### domain_maindomain()
main-domain: main-domain:
@ -474,7 +497,7 @@ domain:
- maindomain - maindomain
api: api:
- GET /domains/main - GET /domains/main
- PUT /domains/main - PUT /domains/<new_main_domain>/main
arguments: arguments:
-n: -n:
full: --new-main-domain full: --new-main-domain
@ -484,8 +507,8 @@ domain:
### certificate_status() ### certificate_status()
cert-status: cert-status:
deprecated: true
action_help: List status of current certificates (all by default). action_help: List status of current certificates (all by default).
api: GET /domains/cert-status/<domain_list>
arguments: arguments:
domain_list: domain_list:
help: Domains to check help: Domains to check
@ -496,8 +519,8 @@ domain:
### certificate_install() ### certificate_install()
cert-install: cert-install:
deprecated: true
action_help: Install Let's Encrypt certificates for given domains (all by default). action_help: Install Let's Encrypt certificates for given domains (all by default).
api: POST /domains/cert-install/<domain_list>
arguments: arguments:
domain_list: domain_list:
help: Domains for which to install the certificates help: Domains for which to install the certificates
@ -517,8 +540,8 @@ domain:
### certificate_renew() ### certificate_renew()
cert-renew: cert-renew:
deprecated: true
action_help: Renew the Let's Encrypt certificates for given domains (all by default). action_help: Renew the Let's Encrypt certificates for given domains (all by default).
api: POST /domains/cert-renew/<domain_list>
arguments: arguments:
domain_list: domain_list:
help: Domains for which to renew the certificates help: Domains for which to renew the certificates
@ -539,7 +562,7 @@ domain:
### domain_url_available() ### domain_url_available()
url-available: url-available:
action_help: Check availability of a web path action_help: Check availability of a web path
api: GET /domain/urlavailable api: GET /domain/<domain>/urlavailable
arguments: arguments:
domain: domain:
help: The domain for the web path (e.g. your.domain.tld) help: The domain for the web path (e.g. your.domain.tld)
@ -548,18 +571,139 @@ domain:
path: path:
help: The path to check (e.g. /coffee) help: The path to check (e.g. /coffee)
subcategories:
### domain_info() config:
# info: subcategory_help: Domain settings
# action_help: Get domain informations actions:
# api: GET /domains/<domain>
# arguments: ### domain_config_get()
# domain: get:
# help: "" action_help: Display a domain configuration
# extra: api: GET /domains/<domain>/config
# pattern: arguments:
# - '^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$' domain:
# - "Must be a valid domain name (e.g. my-domain.org)" help: Domain name
key:
help: A specific panel, section or a question identifier
nargs: '?'
-f:
full: --full
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
### domain_config_set()
set:
action_help: Apply a new configuration
api: PUT /domains/<domain>/config
arguments:
domain:
help: Domain name
key:
help: The question or form key
nargs: '?'
-v:
full: --value
help: new value
-a:
full: --args
help: Serialized arguments for new configuration (i.e. "mail_in=0&mail_out=0")
dns:
subcategory_help: Manage domains DNS
actions:
### domain_dns_conf()
suggest:
action_help: Generate sample DNS configuration for a domain
api:
- GET /domains/<domain>/dns
- GET /domains/<domain>/dns/suggest
arguments:
domain:
help: Target domain
extra:
pattern: *pattern_domain
### domain_dns_push()
push:
action_help: Push DNS records to registrar
api: POST /domains/<domain>/dns/push
arguments:
domain:
help: Domain name to push DNS conf for
extra:
pattern: *pattern_domain
-d:
full: --dry-run
help: Only display what's to be pushed
action: store_true
--force:
help: Also update/remove records which were not originally set by Yunohost, or which have been manually modified
action: store_true
--purge:
help: Delete all records
action: store_true
cert:
subcategory_help: Manage domain certificates
actions:
### certificate_status()
status:
action_help: List status of current certificates (all by default).
api: GET /domains/<domain_list>/cert
arguments:
domain_list:
help: Domains to check
nargs: "*"
--full:
help: Show more details
action: store_true
### certificate_install()
install:
action_help: Install Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert
arguments:
domain_list:
help: Domains for which to install the certificates
nargs: "*"
--force:
help: Install even if current certificate is not self-signed
action: store_true
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to install. (Not recommended)
action: store_true
--self-signed:
help: Install self-signed certificate instead of Let's Encrypt
action: store_true
--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()
renew:
action_help: Renew the Let's Encrypt certificates for given domains (all by default).
api: PUT /domains/<domain_list>/cert/renew
arguments:
domain_list:
help: Domains for which to renew the certificates
nargs: "*"
--force:
help: Ignore the validity threshold (30 days)
action: store_true
--email:
help: Send an email to root with logs if some renewing fails
action: store_true
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
action: store_true
--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
############################# #############################
@ -571,7 +715,7 @@ app:
catalog: catalog:
action_help: Show the catalog of installable application action_help: Show the catalog of installable application
api: GET /appscatalog api: GET /apps/catalog
arguments: arguments:
-f: -f:
full: --full full: --full
@ -589,6 +733,14 @@ app:
string: string:
help: Return matching app name or description with "string" help: Return matching app name or description with "string"
### app_manifest()
manifest:
action_help: Return the manifest of a given app from the catalog, or from a remote git repo
api: GET /apps/manifest
arguments:
app:
help: Name, local path or git URL of the app to fetch the manifest of
fetchlist: fetchlist:
deprecated: true deprecated: true
@ -623,7 +775,7 @@ app:
### app_map() ### app_map()
map: map:
action_help: Show the mapping between urls and apps action_help: Show the mapping between urls and apps
api: GET /appsmap api: GET /apps/map
arguments: arguments:
-a: -a:
full: --app full: --app
@ -660,18 +812,22 @@ app:
help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party) help: Do not ask confirmation if the app is not safe to use (low quality, experimental or 3rd party)
action: store_true action: store_true
### app_remove() TODO: Write help ### app_remove()
remove: remove:
action_help: Remove app action_help: Remove app
api: DELETE /apps/<app> api: DELETE /apps/<app>
arguments: arguments:
app: app:
help: App(s) to delete help: App to remove
-p:
full: --purge
help: Also remove all application data
action: store_true
### app_upgrade() ### app_upgrade()
upgrade: upgrade:
action_help: Upgrade app action_help: Upgrade app
api: PUT /upgrade/apps api: PUT /apps/<app>/upgrade
arguments: arguments:
app: app:
help: App(s) to upgrade (default all) help: App(s) to upgrade (default all)
@ -686,6 +842,10 @@ app:
full: --force full: --force
help: Force the update, even though the app is up to date help: Force the update, even though the app is up to date
action: store_true action: store_true
-b:
full: --no-safety-backup
help: Disable the safety backup during upgrade
action: store_true
### app_change_url() ### app_change_url()
change-url: change-url:
@ -729,7 +889,6 @@ app:
### app_register_url() ### app_register_url()
register-url: register-url:
action_help: Book/register a web path for a given app action_help: Book/register a web path for a given app
api: PUT /tools/registerurl
arguments: arguments:
app: app:
help: App which will use the web path help: App which will use the web path
@ -753,7 +912,6 @@ app:
### app_ssowatconf() ### app_ssowatconf()
ssowatconf: ssowatconf:
action_help: Regenerate SSOwat configuration file action_help: Regenerate SSOwat configuration file
api: PUT /ssowatconf
### app_change_label() ### app_change_label()
change-label: change-label:
@ -768,7 +926,6 @@ app:
### app_addaccess() TODO: Write help ### app_addaccess() TODO: Write help
addaccess: addaccess:
action_help: Grant access right to users (everyone by default) action_help: Grant access right to users (everyone by default)
api: PUT /access
deprecated: true deprecated: true
arguments: arguments:
apps: apps:
@ -780,7 +937,6 @@ app:
### app_removeaccess() TODO: Write help ### app_removeaccess() TODO: Write help
removeaccess: removeaccess:
action_help: Revoke access right to users (everyone by default) action_help: Revoke access right to users (everyone by default)
api: DELETE /access
deprecated: true deprecated: true
arguments: arguments:
apps: apps:
@ -792,7 +948,6 @@ app:
### app_clearaccess() ### app_clearaccess()
clearaccess: clearaccess:
action_help: Reset access rights for the app action_help: Reset access rights for the app
api: POST /access
deprecated: true deprecated: true
arguments: arguments:
apps: apps:
@ -829,24 +984,45 @@ app:
subcategory_help: Applications configuration panel subcategory_help: Applications configuration panel
actions: actions:
### app_config_show_panel() ### app_config_get()
show-panel: get:
action_help: show config panel for the application action_help: Display an app configuration
api: GET /apps/<app>/config-panel api: GET /apps/<app>/config-panel
arguments: arguments:
app: app:
help: App name help: App name
key:
help: A specific panel, section or a question identifier
nargs: '?'
-f:
full: --full
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
### app_config_apply() ### app_config_set()
apply: set:
action_help: apply the new configuration action_help: Apply a new configuration
api: POST /apps/<app>/config api: PUT /apps/<app>/config
arguments: arguments:
app: app:
help: App name help: App name
key:
help: The question or panel key
nargs: '?'
-v:
full: --value
help: new value
-a: -a:
full: --args full: --args
help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path") help: Serialized arguments for new configuration (i.e. "domain=domain.tld&path=/path")
-f:
full: --args-file
help: YAML or JSON file with key/value couples
type: open
############################# #############################
# Backup # # Backup #
@ -858,7 +1034,7 @@ backup:
### backup_create() ### backup_create()
create: create:
action_help: Create a backup local archive. If neither --apps or --system are given, this will backup all apps and all system parts. If only --apps if given, this will only backup apps and no system parts. Similarly, if only --system is given, this will only backup system parts and no apps. action_help: Create a backup local archive. If neither --apps or --system are given, this will backup all apps and all system parts. If only --apps if given, this will only backup apps and no system parts. Similarly, if only --system is given, this will only backup system parts and no apps.
api: POST /backup api: POST /backups
arguments: arguments:
-n: -n:
full: --name full: --name
@ -882,11 +1058,14 @@ backup:
--apps: --apps:
help: List of application names to backup (or all if none given) help: List of application names to backup (or all if none given)
nargs: "*" nargs: "*"
--dry-run:
help: "'Simulate' the backup and return the size details per item to backup"
action: store_true
### backup_restore() ### backup_restore()
restore: restore:
action_help: Restore from a local backup archive. If neither --apps or --system are given, this will restore all apps and all system parts in the archive. If only --apps if given, this will only restore apps and no system parts. Similarly, if only --system is given, this will only restore system parts and no apps. action_help: Restore from a local backup archive. If neither --apps or --system are given, this will restore all apps and all system parts in the archive. If only --apps if given, this will only restore apps and no system parts. Similarly, if only --system is given, this will only restore system parts and no apps.
api: POST /backup/restore/<name> api: PUT /backups/<name>/restore
arguments: arguments:
name: name:
help: Name of the local backup archive help: Name of the local backup archive
@ -903,7 +1082,7 @@ backup:
### backup_list() ### backup_list()
list: list:
action_help: List available local backup archives action_help: List available local backup archives
api: GET /backup/archives api: GET /backups
arguments: arguments:
-i: -i:
full: --with-info full: --with-info
@ -917,7 +1096,7 @@ backup:
### backup_info() ### backup_info()
info: info:
action_help: Show info about a local backup archive action_help: Show info about a local backup archive
api: GET /backup/archives/<name> api: GET /backups/<name>
arguments: arguments:
name: name:
help: Name of the local backup archive help: Name of the local backup archive
@ -933,7 +1112,7 @@ backup:
### backup_download() ### backup_download()
download: download:
action_help: (API only) Request to download the file action_help: (API only) Request to download the file
api: GET /backup/download/<name> api: GET /backups/<name>/download
arguments: arguments:
name: name:
help: Name of the local backup archive help: Name of the local backup archive
@ -941,7 +1120,7 @@ backup:
### backup_delete() ### backup_delete()
delete: delete:
action_help: Delete a backup archive action_help: Delete a backup archive
api: DELETE /backup/archives/<name> api: DELETE /backups/<name>
arguments: arguments:
name: name:
help: Name of the archive to delete help: Name of the archive to delete
@ -1008,7 +1187,6 @@ service:
### service_add() ### service_add()
add: add:
action_help: Add a service action_help: Add a service
# api: POST /services
arguments: arguments:
name: name:
help: Service name to add help: Service name to add
@ -1046,7 +1224,6 @@ service:
### service_remove() ### service_remove()
remove: remove:
action_help: Remove a service action_help: Remove a service
# api: DELETE /services
arguments: arguments:
name: name:
help: Service name to remove help: Service name to remove
@ -1054,7 +1231,7 @@ service:
### service_start() ### service_start()
start: start:
action_help: Start one or more services action_help: Start one or more services
api: PUT /services/<names> api: PUT /services/<names>/start
arguments: arguments:
names: names:
help: Service name to start help: Service name to start
@ -1064,7 +1241,7 @@ service:
### service_stop() ### service_stop()
stop: stop:
action_help: Stop one or more services action_help: Stop one or more services
api: DELETE /services/<names> api: PUT /services/<names>/stop
arguments: arguments:
names: names:
help: Service name to stop help: Service name to stop
@ -1112,7 +1289,7 @@ service:
### service_disable() ### service_disable()
disable: disable:
action_help: Disable one or more services action_help: Disable one or more services
api: DELETE /services/<names>/enable api: PUT /services/<names>/disable
arguments: arguments:
names: names:
help: Service name to disable help: Service name to disable
@ -1147,7 +1324,6 @@ service:
### service_regen_conf() ### service_regen_conf()
regen-conf: regen-conf:
action_help: Regenerate the configuration file(s) for a service action_help: Regenerate the configuration file(s) for a service
api: PUT /services/regenconf
deprecated_alias: deprecated_alias:
- regenconf - regenconf
arguments: arguments:
@ -1199,19 +1375,10 @@ firewall:
help: List forwarded ports with UPnP help: List forwarded ports with UPnP
action: store_true action: store_true
### firewall_reload()
reload:
action_help: Reload all firewall rules
api: PUT /firewall
arguments:
--skip-upnp:
help: Do not refresh port forwarding using UPnP
action: store_true
### firewall_allow() ### firewall_allow()
allow: allow:
action_help: Allow connections on a port action_help: Allow connections on a port
api: POST /firewall/port api: PUT /firewall/<protocol>/allow/<port>
arguments: arguments:
protocol: protocol:
help: "Protocol type to allow (TCP/UDP/Both)" help: "Protocol type to allow (TCP/UDP/Both)"
@ -1241,11 +1408,10 @@ firewall:
help: Do not reload firewall rules help: Do not reload firewall rules
action: store_true action: store_true
### firewall_disallow() ### firewall_disallow()
disallow: disallow:
action_help: Disallow connections on a port action_help: Disallow connections on a port
api: DELETE /firewall/port api: PUT /firewall/<protocol>/disallow/<port>
arguments: arguments:
protocol: protocol:
help: "Protocol type to allow (TCP/UDP/Both)" help: "Protocol type to allow (TCP/UDP/Both)"
@ -1273,11 +1439,10 @@ firewall:
help: Do not reload firewall rules help: Do not reload firewall rules
action: store_true action: store_true
### firewall_upnp() ### firewall_upnp()
upnp: upnp:
action_help: Manage port forwarding using UPnP action_help: Manage port forwarding using UPnP
api: GET /firewall/upnp api: PUT /firewall/upnp/<action>
arguments: arguments:
action: action:
choices: choices:
@ -1291,10 +1456,19 @@ firewall:
help: Do not refresh port forwarding help: Do not refresh port forwarding
action: store_true action: store_true
### firewall_reload()
reload:
action_help: Reload all firewall rules
arguments:
--skip-upnp:
help: Do not refresh port forwarding using UPnP
action: store_true
### firewall_stop() ### firewall_stop()
stop: stop:
action_help: Stop iptables and ip6tables action_help: Stop iptables and ip6tables
api: DELETE /firewall
@ -1308,7 +1482,6 @@ dyndns:
### dyndns_subscribe() ### dyndns_subscribe()
subscribe: subscribe:
action_help: Subscribe to a DynDNS service action_help: Subscribe to a DynDNS service
api: POST /dyndns
arguments: arguments:
--subscribe-host: --subscribe-host:
help: Dynette HTTP API to subscribe to help: Dynette HTTP API to subscribe to
@ -1325,7 +1498,6 @@ dyndns:
### dyndns_update() ### dyndns_update()
update: update:
action_help: Update IP on DynDNS platform action_help: Update IP on DynDNS platform
api: PUT /dyndns
arguments: arguments:
--dyn-host: --dyn-host:
help: Dynette DNS server to inform help: Dynette DNS server to inform
@ -1355,13 +1527,11 @@ dyndns:
### dyndns_installcron() ### dyndns_installcron()
installcron: installcron:
action_help: Install IP update cron deprecated: true
api: POST /dyndns/cron
### dyndns_removecron() ### dyndns_removecron()
removecron: removecron:
action_help: Remove IP update cron deprecated: true
api: DELETE /dyndns/cron
############################# #############################
@ -1398,9 +1568,9 @@ tools:
postinstall: postinstall:
action_help: YunoHost post-install action_help: YunoHost post-install
api: POST /postinstall api: POST /postinstall
configuration: authentication:
# We need to be able to run the postinstall without being authenticated, otherwise we can't run the postinstall # We need to be able to run the postinstall without being authenticated, otherwise we can't run the postinstall
authenticate: false api: null
arguments: arguments:
-d: -d:
full: --domain full: --domain
@ -1424,32 +1594,47 @@ tools:
help: Use this if you really want to set a weak password help: Use this if you really want to set a weak password
action: store_true action: store_true
--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
api: PUT /update api: PUT /update/<target>
arguments: arguments:
target:
help: What to update, "apps" (application catalog) or "system" (fetch available package upgrades, equivalent to apt update), "all" for both
choices:
- apps
- system
- all
nargs: "?"
metavar: TARGET
default: all
--apps: --apps:
help: Fetch the application list to check which apps can be upgraded help: (Deprecated, see first positional arg) Fetch the application list to check which apps can be upgraded
action: store_true action: store_true
--system: --system:
help: Fetch available system packages upgrades (equivalent to apt update) help: (Deprecated, see first positional arg) Fetch available system packages upgrades (equivalent to apt update)
action: store_true action: store_true
### tools_upgrade() ### tools_upgrade()
upgrade: upgrade:
action_help: YunoHost upgrade action_help: YunoHost upgrade
api: PUT /upgrade api: PUT /upgrade/<target>
arguments: arguments:
target:
help: What to upgrade, either "apps" (all apps) or "system" (all system packages)
choices:
- apps
- system
nargs: "?"
--apps: --apps:
help: List of apps to upgrade (all by default) help: (Deprecated, see first positional arg) Upgrade all applications
nargs: "*" action: store_true
--system: --system:
help: Upgrade only the system packages help: (Deprecated, see first positional arg) Upgrade only the system packages
action: store_true action: store_true
### tools_shell() ### tools_shell()
@ -1483,7 +1668,9 @@ tools:
### tools_regen_conf() ### tools_regen_conf()
regen-conf: regen-conf:
action_help: Regenerate the configuration file(s) action_help: Regenerate the configuration file(s)
api: PUT /tools/regenconf api:
- PUT /regenconf
- PUT /regenconf/<names>
arguments: arguments:
names: names:
help: Categories to regenerate configuration of (all by default) help: Categories to regenerate configuration of (all by default)
@ -1532,7 +1719,9 @@ tools:
### tools_migrations_run() ### tools_migrations_run()
run: run:
action_help: Run migrations action_help: Run migrations
api: POST /migrations/run api:
- PUT /migrations
- PUT /migrations/<targets>
deprecated_alias: deprecated_alias:
- migrate - migrate
arguments: arguments:
@ -1555,7 +1744,6 @@ tools:
### tools_migrations_state() ### tools_migrations_state()
state: state:
action_help: Show current migrations state action_help: Show current migrations state
api: GET /migrations/state
############################# #############################
@ -1584,7 +1772,6 @@ hook:
### hook_info() ### hook_info()
info: info:
action_help: Get information about a given hook action_help: Get information about a given hook
api: GET /hooks/<action>/<name>
arguments: arguments:
action: action:
help: Action name help: Action name
@ -1614,7 +1801,6 @@ hook:
### hook_callback() ### hook_callback()
callback: callback:
action_help: Execute all scripts binded to an action action_help: Execute all scripts binded to an action
api: POST /hooks/<action>
arguments: arguments:
action: action:
help: Action name help: Action name
@ -1710,7 +1896,7 @@ log:
### log_share() ### log_share()
share: share:
action_help: Share the full log on yunopaste (alias to show --share) action_help: Share the full log on yunopaste (alias to show --share)
api: GET /logs/share api: GET /logs/<path>/share
arguments: arguments:
path: path:
help: Log file to share help: Log file to share
@ -1725,11 +1911,11 @@ diagnosis:
list: list:
action_help: List diagnosis categories action_help: List diagnosis categories
api: GET /diagnosis/list api: GET /diagnosis/categories
show: show:
action_help: Show most recents diagnosis results action_help: Show most recents diagnosis results
api: GET /diagnosis/show api: GET /diagnosis
arguments: arguments:
categories: categories:
help: Diagnosis categories to display (all by default) help: Diagnosis categories to display (all by default)
@ -1747,9 +1933,20 @@ diagnosis:
help: Show a human-readable output help: Show a human-readable output
action: store_true action: store_true
get:
action_help: Low-level command to fetch raw data and status about a specific diagnosis test
api: GET /diagnosis/<category>
arguments:
category:
help: Diagnosis category to fetch results from
item:
help: "List of criteria describing the test. Must correspond exactly to the 'meta' infos in 'yunohost diagnosis show'"
metavar: CRITERIA
nargs: "*"
run: run:
action_help: Run diagnosis action_help: Run diagnosis
api: POST /diagnosis/run api: PUT /diagnosis/run
arguments: arguments:
categories: categories:
help: Diagnosis categories to run (all by default) help: Diagnosis categories to run (all by default)
@ -1766,27 +1963,21 @@ diagnosis:
ignore: ignore:
action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues
api: POST /diagnosis/ignore api: PUT /diagnosis/ignore
arguments: arguments:
--add-filter: --filter:
help: "Add a filter. The first element should be a diagnosis category, and other criterias can be provided using the infos from the 'meta' sections in 'yunohost diagnosis show'. For example: 'dnsrecords domain=yolo.test category=xmpp'" help: "Add a filter. The first element should be a diagnosis category, and other criterias can be provided using the infos from the 'meta' sections in 'yunohost diagnosis show'. For example: 'dnsrecords domain=yolo.test category=xmpp'"
nargs: "*" nargs: "*"
metavar: CRITERIA metavar: CRITERIA
--remove-filter:
help: Remove a filter (it should be an existing filter as listed with --list)
nargs: "*"
metavar: CRITERIA
--list: --list:
help: List active ignore filters help: List active ignore filters
action: store_true action: store_true
get: unignore:
action_help: Low-level command to fetch raw data and status about a specific diagnosis test action_help: Configure some diagnosis results to be unignored and therefore considered as actual issues
api: GET /diagnosis/item/<category> api: PUT /diagnosis/unignore
arguments: arguments:
category: --filter:
help: Diagnosis category to fetch results from help: Remove a filter (it should be an existing filter as listed with --list)
item:
help: "List of criteria describing the test. Must correspond exactly to the 'meta' infos in 'yunohost diagnosis show'"
metavar: CRITERIA
nargs: "*" nargs: "*"
metavar: CRITERIA

View file

@ -13,6 +13,7 @@ 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 + "/yunohost.yml" ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/yunohost.yml"
os.system(f"mkdir {THIS_SCRIPT_DIR}/../bash-completion.d")
BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost" BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/../bash-completion.d/yunohost"
@ -32,7 +33,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.load(stream) OPTION_TREE = yaml.safe_load(stream)
CATEGORY = [ CATEGORY = [
category for category in OPTION_TREE.keys() if not category.startswith("_") category for category in OPTION_TREE.keys() if not category.startswith("_")

View file

@ -1,3 +0,0 @@
# This file is automatically generated
# during Debian's package build by the script
# data/actionsmap/yunohost_completion.py

View file

@ -12,31 +12,27 @@ ynh_wait_dpkg_free() {
local try local try
set +o xtrace # set +x set +o xtrace # set +x
# With seq 1 17, timeout will be almost 30 minutes # With seq 1 17, timeout will be almost 30 minutes
for try in `seq 1 17` for try in $(seq 1 17); do
do
# Check if /var/lib/dpkg/lock is used by another process # Check if /var/lib/dpkg/lock is used by another process
if lsof /var/lib/dpkg/lock > /dev/null if lsof /var/lib/dpkg/lock >/dev/null; then
then
echo "apt is already in use..." echo "apt is already in use..."
# Sleep an exponential time at each round # Sleep an exponential time at each round
sleep $(( try * try )) sleep $((try * try))
else else
# Check if dpkg hasn't been interrupted and is fully available. # Check if dpkg hasn't been interrupted and is fully available.
# See this for more information: https://sources.debian.org/src/apt/1.4.9/apt-pkg/deb/debsystem.cc/#L141-L174 # See this for more information: https://sources.debian.org/src/apt/1.4.9/apt-pkg/deb/debsystem.cc/#L141-L174
local dpkg_dir="/var/lib/dpkg/updates/" local dpkg_dir="/var/lib/dpkg/updates/"
# For each file in $dpkg_dir # For each file in $dpkg_dir
while read dpkg_file <&9 while read dpkg_file <&9; do
do
# Check if the name of this file contains only numbers. # Check if the name of this file contains only numbers.
if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$" if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$"; then
then
# If so, that a remaining of dpkg. # If so, that a remaining of dpkg.
ynh_print_err "dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem." ynh_print_err "dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
set -o xtrace # set -x set -o xtrace # set -x
return 1 return 1
fi fi
done 9<<< "$(ls -1 $dpkg_dir)" done 9<<<"$(ls -1 $dpkg_dir)"
set -o xtrace # set -x set -o xtrace # set -x
return 0 return 0
fi fi
@ -47,16 +43,17 @@ ynh_wait_dpkg_free() {
# Check either a package is installed or not # Check either a package is installed or not
# #
# example: ynh_package_is_installed --package=yunohost && echo "ok" # example: ynh_package_is_installed --package=yunohost && echo "installed"
# #
# usage: ynh_package_is_installed --package=name # usage: ynh_package_is_installed --package=name
# | arg: -p, --package= - the package name to check # | arg: -p, --package= - the package name to check
# | ret: 0 if the package is installed, 1 else.
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_package_is_installed() { ynh_package_is_installed() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=package= ) local -A args_array=([p]=package=)
local package local package
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -78,13 +75,12 @@ ynh_package_is_installed() {
ynh_package_version() { ynh_package_version() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=package= ) local -A args_array=([p]=package=)
local package local package
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if ynh_package_is_installed "$package" if ynh_package_is_installed "$package"; then
then
dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null
else else
echo '' echo ''
@ -165,7 +161,7 @@ ynh_package_autopurge() {
# | arg: controlfile - path of the equivs control file # | arg: controlfile - path of the equivs control file
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_package_install_from_equivs () { ynh_package_install_from_equivs() {
local controlfile=$1 local controlfile=$1
# retrieve package information # retrieve package information
@ -181,7 +177,7 @@ ynh_package_install_from_equivs () {
local TMPDIR=$(mktemp --directory) local TMPDIR=$(mktemp --directory)
# Force the compatibility level at 10, levels below are deprecated # Force the compatibility level at 10, levels below are deprecated
echo 10 > /usr/share/equivs/template/debian/compat 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
@ -189,12 +185,14 @@ ynh_package_install_from_equivs () {
# 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}/control"
(cd "$TMPDIR" (
LC_ALL=C equivs-build ./control 1> /dev/null cd "$TMPDIR"
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log) LC_ALL=C equivs-build ./control 1>/dev/null
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log
)
ynh_package_install --fix-broken || \ ynh_package_install --fix-broken \
{ # If the installation failed || { # If the installation failed
# (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process) # (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process)
# Parse the list of problematic dependencies from dpkg's log ... # Parse the list of problematic dependencies from dpkg's log ...
# (relevant lines look like: "foo-ynh-deps depends on bar; however:") # (relevant lines look like: "foo-ynh-deps depends on bar; however:")
@ -202,13 +200,16 @@ ynh_package_install_from_equivs () {
# Fake an install of those dependencies to see the errors # Fake an install of those dependencies to see the errors
# The sed command here is, Print only from 'Reading state info' to the end. # The sed command here is, Print only from 'Reading state info' to the end.
[[ -n "$problematic_dependencies" ]] && ynh_package_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2 [[ -n "$problematic_dependencies" ]] && ynh_package_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2
ynh_die --message="Unable to install dependencies"; } ynh_die --message="Unable to install dependencies"
}
[[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir. [[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir.
# check if the package is actually installed # check if the package is actually installed
ynh_package_is_installed "$pkgname" ynh_package_is_installed "$pkgname"
} }
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="true"
# Define and install dependencies with a equivs control file # Define and install dependencies with a equivs control file
# #
# This helper can/should only be called once per app # This helper can/should only be called once per app
@ -216,28 +217,25 @@ ynh_package_install_from_equivs () {
# example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5" # example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
# #
# usage: ynh_install_app_dependencies dep [dep [...]] # usage: ynh_install_app_dependencies dep [dep [...]]
# | arg: dep - the package name to install in dependence. Writing "dep3|dep4|dep5" can be used to specify alternatives. For example : dep1 dep2 "dep3|dep4|dep5" will require to install dep1 and dep 2 and (dep3 or dep4 or dep5). # | arg: dep - the package name to install in dependence.
# | arg: "dep1|dep2|…" - You can specify alternatives. It will require to install (dep1 or dep2, etc).
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_install_app_dependencies () { ynh_install_app_dependencies() {
local dependencies=$@ local 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="../manifest.json" local manifest_path="$YNH_APP_BASEDIR/manifest.json"
if [ ! -e "$manifest_path" ]; then
manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
fi
local version=$(grep '\"version\": ' "$manifest_path" | cut --delimiter='"' --fields=4) # Retrieve the version number in the manifest file. local version=$(jq -r '.version' "$manifest_path")
if [ ${#version} -eq 0 ]; then if [ -z "${version}" ] || [ "$version" == "null" ]; then
version="1.0" version="1.0"
fi fi
local dep_app=${app//_/-} # Replace all '_' by '-' local dep_app=${app//_/-} # Replace all '_' by '-'
# Handle specific versions # Handle specific versions
if [[ "$dependencies" =~ [\<=\>] ]] if [[ "$dependencies" =~ [\<=\>] ]]; then
then
# Replace version specifications by relationships syntax # Replace version specifications by relationships syntax
# https://www.debian.org/doc/debian-policy/ch-relationships.html # https://www.debian.org/doc/debian-policy/ch-relationships.html
# Sed clarification # Sed clarification
@ -249,27 +247,62 @@ ynh_install_app_dependencies () {
dependencies="$(echo "$dependencies" | sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g')" dependencies="$(echo "$dependencies" | sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g')"
fi fi
# Check for specific php dependencies which requires sury
# This grep will for example return "7.4" if dependencies is "foo bar php7.4-pwet php-gni"
# The (?<=php) syntax corresponds to lookbehind ;)
local specific_php_version=$(echo $dependencies | grep -oP '(?<=php)[0-9.]+(?=-|\>)' | sort -u)
# 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
[[ $(echo $specific_php_version | wc -l) -eq 1 ]] \
|| 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"
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 # 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 # 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 # https://github.com/YunoHost/issues/issues/1407
# #
# If we require to install php dependency # If we require to install php dependency
if echo $dependencies | grep --quiet 'php' if grep --quiet 'php' <<< "$dependencies"; then
then
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) # 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" if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9"; then
then
# And sury ain't already in sources.lists # And sury ain't already in sources.lists
if ! grep --recursive --quiet "^ *deb.*sury" /etc/apt/sources.list* if ! grep --recursive --quiet "^ *deb.*sury" /etc/apt/sources.list*; then
then
# Re-add sury # Re-add sury
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 ynh_add_sury
fi fi
fi fi
fi fi
cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build cat >/tmp/${dep_app}-ynh-deps.control <<EOF # Make a control file for equivs-build
Section: misc Section: misc
Priority: optional Priority: optional
Package: ${dep_app}-ynh-deps Package: ${dep_app}-ynh-deps
@ -282,39 +315,55 @@ EOF
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \ 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 || ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
rm /tmp/${dep_app}-ynh-deps.control rm /tmp/${dep_app}-ynh-deps.control
ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies" ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies"
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
# Store phpversion into the config of this app
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
# Integrate new php-fpm service in yunohost
yunohost service add php${specific_php_version}-fpm --log "/var/log/php${phpversion}-fpm.log"
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
fi
} }
# Add sury repository with adequate pin strategy
#
# [internal]
#
# usage: ynh_add_sury
#
ynh_add_sury() {
# Add an extra repository for those packages
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
}
# Add dependencies to install with ynh_install_app_dependencies # Add dependencies to install with ynh_install_app_dependencies
# #
# 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.
# | arg: -r, --replace - Replace dependencies instead of adding to existing ones.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_add_app_dependencies () { ynh_add_app_dependencies() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=pr local legacy_args=pr
local -A args_array=( [p]=package= [r]=replace) local -A args_array=([p]=package= [r]=replace)
local package local package
local replace
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
replace=${replace:-0}
local current_dependencies="" ynh_print_warn --message="Packagers: ynh_add_app_dependencies is deprecated and is now only an alias to ynh_install_app_dependencies"
if [ $replace -eq 0 ] ynh_install_app_dependencies "${package}"
then
local dep_app=${app//_/-} # Replace all '_' by '-'
if ynh_package_is_installed --package="${dep_app}-ynh-deps"
then
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
fi
current_dependencies=${current_dependencies// | /|}
fi
ynh_install_app_dependencies "${current_dependencies}${package}"
} }
# Remove fake package and its dependencies # Remove fake package and its dependencies
@ -324,9 +373,26 @@ ynh_add_app_dependencies () {
# usage: ynh_remove_app_dependencies # usage: ynh_remove_app_dependencies
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_remove_app_dependencies () { ynh_remove_app_dependencies() {
local dep_app=${app//_/-} # Replace all '_' by '-' local dep_app=${app//_/-} # Replace all '_' by '-'
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
ynh_package_autopurge ${dep_app}-ynh-deps # 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.
# Check if this app used a specific php version ... in which case we check
# if the corresponding php-fpm is still there. Otherwise, we remove the
# 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
} }
# Install packages from an extra repository properly. # Install packages from an extra repository properly.
@ -338,10 +404,10 @@ ynh_remove_app_dependencies () {
# | 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.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_install_extra_app_dependencies () { ynh_install_extra_app_dependencies() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=rpkn local legacy_args=rpkn
local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) local -A args_array=([r]=repo= [p]=package= [k]=key= [n]=name=)
local repo local repo
local package local package
local key local key
@ -352,15 +418,14 @@ ynh_install_extra_app_dependencies () {
key=${key:-} key=${key:-}
# Set a key only if asked # Set a key only if asked
if [ -n "$key" ] if [ -n "$key" ]; then
then
key="--key=$key" key="--key=$key"
fi fi
# Add an extra repository for those packages # Add an extra repository for those packages
ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name
# Install requested dependencies from this extra repository. # Install requested dependencies from this extra repository.
ynh_add_app_dependencies --package="$package" ynh_install_app_dependencies "$package"
# Remove this extra repository after packages are installed # Remove this extra repository after packages are installed
ynh_remove_extra_repo --name=$app ynh_remove_extra_repo --name=$app
@ -378,10 +443,10 @@ ynh_install_extra_app_dependencies () {
# | arg: -a, --append - Do not overwrite existing files. # | arg: -a, --append - Do not overwrite existing files.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_install_extra_repo () { ynh_install_extra_repo() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=rkpna local legacy_args=rkpna
local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) local -A args_array=([r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append)
local repo local repo
local key local key
local priority local priority
@ -394,8 +459,7 @@ ynh_install_extra_repo () {
key=${key:-} key=${key:-}
priority=${priority:-} priority=${priority:-}
if [ $append -eq 1 ] if [ $append -eq 1 ]; then
then
append="--append" append="--append"
wget_append="tee --append" wget_append="tee --append"
else else
@ -424,18 +488,16 @@ ynh_install_extra_repo () {
local pin="${uri#*://}" local pin="${uri#*://}"
pin="${pin%%/*}" pin="${pin%%/*}"
# Set a priority only if asked # Set a priority only if asked
if [ -n "$priority" ] if [ -n "$priority" ]; then
then
priority="--priority=$priority" priority="--priority=$priority"
fi fi
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" ] if [ -n "$key" ]; then
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
fi fi
# Update the list of package with the new repo # Update the list of package with the new repo
@ -450,20 +512,20 @@ ynh_install_extra_repo () {
# | 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.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_remove_extra_repo () { ynh_remove_extra_repo() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=n local legacy_args=n
local -A args_array=( [n]=name= ) local -A args_array=([n]=name=)
local name local name
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
name="${name:-$app}" name="${name:-$app}"
ynh_secure_remove "/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"
ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.gpg" > /dev/null ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.gpg" >/dev/null
ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.asc" > /dev/null ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.asc" >/dev/null
# 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
@ -485,10 +547,10 @@ ynh_remove_extra_repo () {
# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable # ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable
# #
# 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=uscna local legacy_args=uscna
local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) 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
@ -499,8 +561,7 @@ ynh_add_repo () {
name="${name:-$app}" name="${name:-$app}"
append=${append:-0} append=${append:-0}
if [ $append -eq 1 ] if [ $append -eq 1 ]; then
then
append="tee --append" append="tee --append"
else else
append="tee" append="tee"
@ -526,10 +587,10 @@ ynh_add_repo () {
# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning. # See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_pin_repo () { ynh_pin_repo() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=pirna local legacy_args=pirna
local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) local -A args_array=([p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append)
local package local package
local pin local pin
local priority local priority
@ -542,8 +603,7 @@ ynh_pin_repo () {
name="${name:-$app}" name="${name:-$app}"
append=${append:-0} append=${append:-0}
if [ $append -eq 1 ] if [ $append -eq 1 ]; then
then
append="tee --append" append="tee --append"
else else
append="tee" append="tee"

View file

@ -13,13 +13,13 @@ CAN_BIND=${CAN_BIND:-1}
# #
# 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
# #
# Details: ynh_backup writes SRC and the relative DEST into a CSV file. And it # `ynh_backup` writes `src_path` and the relative `dest_path` into a CSV file, and it
# creates the parent destination directory # creates the parent destination directory
# #
# If DEST is ended by a slash it complete this path with the basename of SRC. # If `dest_path` is ended by a slash it complete this path with the basename of `src_path`.
#
# Example in the context of a wordpress app
# #
# Example in the context of a wordpress app :
# ```
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
# # => This line will be added into CSV file # # => This line will be added into CSV file
# # "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf" # # "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf"
@ -40,32 +40,34 @@ CAN_BIND=${CAN_BIND:-1}
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/" # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" # # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
# #
# ```
# #
# How to use --is_big: # How to use `--is_big`:
# --is_big is used to specify that this part of the backup can be quite huge. #
# `--is_big` is used to specify that this part of the backup can be quite huge.
# So, you don't want that your package does backup that part during ynh_backup_before_upgrade. # So, you don't want that your package does backup that part during ynh_backup_before_upgrade.
# In the same way, an user may doesn't want to backup this big part of the app for # In the same way, an user may doesn't want to backup this big part of the app for
# each of his backup. And so handle that part differently. # each of his backup. And so handle that part differently.
# #
# As this part of your backup may not be done, your restore script has to handle it. # As this part of your backup may not be done, your restore script has to handle it.
# In your restore script, use --not_mandatory with ynh_restore_file # In your restore script, use `--not_mandatory` with `ynh_restore_file`
# As well in your remove script, you should not remove those data ! Or an user may end up with # As well in your remove script, you should not remove those data ! Or an user may end up with
# a failed upgrade restoring an app without data anymore ! # a failed upgrade restoring an app without data anymore !
# #
# To have the benefit of --is_big while doing a backup, you can whether set the environement # To have the benefit of `--is_big` while doing a backup, you can whether set the environement
# variable BACKUP_CORE_ONLY to 1 (BACKUP_CORE_ONLY=1) before the backup command. It will affect # variable `BACKUP_CORE_ONLY` to 1 (`BACKUP_CORE_ONLY=1`) before the backup command. It will affect
# only that backup command. # only that backup command.
# Or set the config do_not_backup_data to 1 into the settings.yml of the app. This will affect # Or set the config `do_not_backup_data` to 1 into the `settings.yml` of the app. This will affect
# all backups for this app until the setting is removed. # all backups for this app until the setting is removed.
# #
# Requires YunoHost version 2.4.0 or higher. # Requires YunoHost version 2.4.0 or higher.
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory # Requires YunoHost version 3.5.0 or higher for the argument `--not_mandatory`
ynh_backup() { ynh_backup() {
# TODO find a way to avoid injection by file strange naming ! # TODO find a way to avoid injection by file strange naming !
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=sdbm local legacy_args=sdbm
local -A args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory ) local -A args_array=([s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory)
local src_path local src_path
local dest_path local dest_path
local is_big local is_big
@ -81,10 +83,8 @@ ynh_backup() {
# If backing up core only (used by ynh_backup_before_upgrade), # If backing up core only (used by ynh_backup_before_upgrade),
# don't backup big data items # don't backup big data items
if [ $is_big -eq 1 ] && ( [ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ] ) if [ $is_big -eq 1 ] && ([ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ]); then
then if [ $BACKUP_CORE_ONLY -eq 1 ]; then
if [ $BACKUP_CORE_ONLY -eq 1 ]
then
ynh_print_info --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set." ynh_print_info --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set."
else else
ynh_print_info --message="$src_path will not be saved, because 'do_not_backup_data' is set." ynh_print_info --message="$src_path will not be saved, because 'do_not_backup_data' is set."
@ -96,14 +96,11 @@ ynh_backup() {
# Format correctly source and destination paths # Format correctly source and destination paths
# ============================================================================== # ==============================================================================
# Be sure the source path is not empty # Be sure the source path is not empty
if [ ! -e "$src_path" ] if [ ! -e "$src_path" ]; then
then
ynh_print_warn --message="Source path '${src_path}' does not exist" ynh_print_warn --message="Source path '${src_path}' does not exist"
if [ "$not_mandatory" == "0" ] if [ "$not_mandatory" == "0" ]; then
then
# This is a temporary fix for fail2ban config files missing after the migration to stretch. # This is a temporary fix for fail2ban config files missing after the migration to stretch.
if echo "${src_path}" | grep --quiet "/etc/fail2ban" if echo "${src_path}" | grep --quiet "/etc/fail2ban"; then
then
touch "${src_path}" touch "${src_path}"
ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!" ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!"
else else
@ -121,13 +118,11 @@ ynh_backup() {
# If there is no destination path, initialize it with the source path # If there is no destination path, initialize it with the source path
# relative to "/". # relative to "/".
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost # eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
if [[ -z "$dest_path" ]] if [[ -z "$dest_path" ]]; then
then
dest_path="${src_path#/}" dest_path="${src_path#/}"
else else
if [[ "${dest_path:0:1}" == "/" ]] if [[ "${dest_path:0:1}" == "/" ]]; then
then
# If the destination path is an absolute path, transform it as a path # If the destination path is an absolute path, transform it as a path
# relative to the current working directory ($YNH_CWD) # relative to the current working directory ($YNH_CWD)
@ -151,8 +146,7 @@ ynh_backup() {
fi fi
# Check if dest_path already exists in tmp archive # Check if dest_path already exists in tmp archive
if [[ -e "${dest_path}" ]] if [[ -e "${dest_path}" ]]; then
then
ynh_print_err --message="Destination path '${dest_path}' already exist" ynh_print_err --message="Destination path '${dest_path}' already exist"
return 1 return 1
fi fi
@ -169,7 +163,7 @@ ynh_backup() {
# ============================================================================== # ==============================================================================
local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g') local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g')
local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g') local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g')
echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}" echo "\"${src}\",\"${dest}\"" >>"${YNH_BACKUP_CSV}"
# ============================================================================== # ==============================================================================
@ -183,15 +177,14 @@ ynh_backup() {
# usage: ynh_restore # usage: ynh_restore
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_restore () { ynh_restore() {
# Deduce the relative path of $YNH_CWD # Deduce the relative path of $YNH_CWD
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}" local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
REL_DIR="${REL_DIR%/}/" REL_DIR="${REL_DIR%/}/"
# For each destination path begining by $REL_DIR # For each destination path begining by $REL_DIR
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" | \ cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" \
while read line | while read line; do
do
local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)") local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)")
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)") local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH" ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
@ -203,16 +196,16 @@ ynh_restore () {
# [internal] # [internal]
# #
# usage: _get_archive_path ORIGIN_PATH # usage: _get_archive_path ORIGIN_PATH
_get_archive_path () { _get_archive_path() {
# For security reasons we use csv python library to read the CSV # For security reasons we use csv python library to read the CSV
python -c " python3 -c "
import sys import sys
import csv import csv
with open(sys.argv[1], 'r') as backup_file: with open(sys.argv[1], 'r') as backup_file:
backup_csv = csv.DictReader(backup_file, fieldnames=['source', 'dest']) backup_csv = csv.DictReader(backup_file, fieldnames=['source', 'dest'])
for row in backup_csv: for row in backup_csv:
if row['source']==sys.argv[2].strip('\"'): if row['source']==sys.argv[2].strip('\"'):
print row['dest'] print(row['dest'])
sys.exit(0) sys.exit(0)
raise Exception('Original path for %s not found' % sys.argv[2]) raise Exception('Original path for %s not found' % sys.argv[2])
" "${YNH_BACKUP_CSV}" "$1" " "${YNH_BACKUP_CSV}" "$1"
@ -221,33 +214,32 @@ with open(sys.argv[1], 'r') as backup_file:
# Restore a file or a directory # Restore a file or a directory
# #
# Use the registered path in backup_list by ynh_backup to restore the file at
# the right place.
#
# usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory] # usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]
# | arg: -o, --origin_path= - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive # | arg: -o, --origin_path= - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive
# | arg: -d, --dest_path= - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv # | arg: -d, --dest_path= - Path where restore the file or the dir. If unspecified, the destination will be `ORIGIN_PATH` or if the `ORIGIN_PATH` doesn't exist in the archive, the destination will be searched into `backup.csv`
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it. # | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it.
# #
# Use the registered path in backup_list by ynh_backup to restore the file at the right place.
#
# examples: # examples:
# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf" # ynh_restore_file -o "/etc/nginx/conf.d/$domain.d/$app.conf"
# # You can also use relative paths: # # You can also use relative paths:
# ynh_restore_file "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
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed. # `/home/yunohost.conf/backup/`. Otherwise, the existing file is removed.
# #
# if apps/wordpress/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`
# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into # if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into
# /etc/nginx/conf.d/$domain.d/$app.conf # `/etc/nginx/conf.d/$domain.d/$app.conf`
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory # Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
ynh_restore_file () { ynh_restore_file() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=odm local legacy_args=odm
local -A args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory ) local -A args_array=([o]=origin_path= [d]=dest_path= [m]=not_mandatory)
local origin_path local origin_path
local dest_path local dest_path
local not_mandatory local not_mandatory
@ -260,10 +252,8 @@ ynh_restore_file () {
local archive_path="$YNH_CWD${origin_path}" local archive_path="$YNH_CWD${origin_path}"
# If archive_path doesn't exist, search for a corresponding path in CSV # If archive_path doesn't exist, search for a corresponding path in CSV
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ] if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
then if [ "$not_mandatory" == "0" ]; then
if [ "$not_mandatory" == "0" ]
then
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")" archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
else else
return 0 return 0
@ -271,11 +261,9 @@ ynh_restore_file () {
fi fi
# Move the old directory if it already exists # Move the old directory if it already exists
if [[ -e "${dest_path}" ]] if [[ -e "${dest_path}" ]]; then
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" ]] if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]; then
then
local backup_file="/home/yunohost.conf/backup/${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
@ -288,10 +276,8 @@ ynh_restore_file () {
mkdir --parents $(dirname "$dest_path") mkdir --parents $(dirname "$dest_path")
# Do a copy if it's just a mounting point # Do a copy if it's just a mounting point
if mountpoint --quiet $YNH_BACKUP_DIR if mountpoint --quiet $YNH_BACKUP_DIR; then
then if [[ -d "${archive_path}" ]]; then
if [[ -d "${archive_path}" ]]
then
archive_path="${archive_path}/." archive_path="${archive_path}/."
mkdir --parents "$dest_path" mkdir --parents "$dest_path"
fi fi
@ -322,20 +308,32 @@ ynh_bind_or_cp() {
# $app should be defined when calling this helper # $app should be defined when calling this helper
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_store_file_checksum () { ynh_store_file_checksum() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=([f]=file= [u]=update_only)
local file local file
local update_only
update_only="${update_only:-0}"
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
# If update only, we don't save the new checksum if no old checksum exist
if [ $update_only -eq 1 ]; then
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
if [ -z "${checksum_value}" ]; then
unset backup_file_checksum
return 0
fi
fi
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 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-}" ] if [ -n "${backup_file_checksum-}" ]; then
then
# Print the diff between the previous file and the new one. # Print the diff between the previous file and the new one.
# diff return 1 if the files are different, so the || true # diff return 1 if the files are different, so the || true
diff --report-identical-files --unified --color=always $backup_file_checksum $file >&2 || true diff --report-identical-files --unified --color=always $backup_file_checksum $file >&2 || true
@ -346,18 +344,18 @@ ynh_store_file_checksum () {
# Verify the checksum and backup the file if it's different # Verify the checksum and backup the file if it's different
# #
# This helper is primarily meant to allow to easily backup personalised/manually
# modified config files.
#
# usage: ynh_backup_if_checksum_is_different --file=file # usage: ynh_backup_if_checksum_is_different --file=file
# | arg: -f, --file= - The file on which the checksum test will be perfomed. # | arg: -f, --file= - The file on which the checksum test will be perfomed.
# | ret: the name of a backup file, or nothing # | ret: the name of a backup file, or nothing
# #
# This helper is primarily meant to allow to easily backup personalised/manually
# modified config files.
#
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_backup_if_checksum_is_different () { ynh_backup_if_checksum_is_different() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=([f]=file=)
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -366,10 +364,8 @@ ynh_backup_if_checksum_is_different () {
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name) local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
# backup_file_checksum isn't declare as local, so it can be reuse by ynh_store_file_checksum # backup_file_checksum isn't declare as local, so it can be reuse by ynh_store_file_checksum
backup_file_checksum="" backup_file_checksum=""
if [ -n "$checksum_value" ] if [ -n "$checksum_value" ]; then # Proceed only if a value was stored into the app settings
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="/home/yunohost.conf/backup/$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
@ -387,10 +383,10 @@ ynh_backup_if_checksum_is_different () {
# $app should be defined when calling this helper # $app should be defined when calling this helper
# #
# Requires YunoHost version 3.3.1 or higher. # Requires YunoHost version 3.3.1 or higher.
ynh_delete_file_checksum () { ynh_delete_file_checksum() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=([f]=file=)
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -399,19 +395,31 @@ ynh_delete_file_checksum () {
ynh_app_setting_delete --app=$app --key=$checksum_setting_name ynh_app_setting_delete --app=$app --key=$checksum_setting_name
} }
# Checks a backup archive exists
#
# [internal]
#
ynh_backup_archive_exists() {
yunohost backup list --output-as json --quiet \
| jq -e --arg archive "$1" '.archives | index($archive)' >/dev/null
}
# Make a backup in case of failed upgrade # Make a backup in case of failed upgrade
# #
# usage: # usage: ynh_backup_before_upgrade
#
# Usage in a package script:
# ```
# ynh_backup_before_upgrade # ynh_backup_before_upgrade
# ynh_clean_setup () { # ynh_clean_setup () {
# ynh_restore_upgradebackup # ynh_restore_upgradebackup
# } # }
# ynh_abort_if_errors # ynh_abort_if_errors
# ```
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 2.7.2 or higher.
ynh_backup_before_upgrade () { ynh_backup_before_upgrade() {
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ] if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]; then
then
ynh_print_warn --message="This app doesn't have any backup script." ynh_print_warn --message="This app doesn't have any backup script."
return return
fi fi
@ -420,11 +428,9 @@ ynh_backup_before_upgrade () {
local app_bck=${app//_/-} # Replace all '_' by '-' local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0} NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ] if [ "$NO_BACKUP_UPGRADE" -eq 0 ]; then
then
# Check if a backup already exists with the prefix 1 # Check if a backup already exists with the prefix 1
if yunohost backup list | grep --quiet $app_bck-pre-upgrade1 if ynh_backup_archive_exists "$app_bck-pre-upgrade1"; then
then
# Prefix becomes 2 to preserve the previous backup # Prefix becomes 2 to preserve the previous backup
backup_number=2 backup_number=2
old_backup_number=1 old_backup_number=1
@ -432,13 +438,11 @@ ynh_backup_before_upgrade () {
# Create backup # Create backup
BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
if [ "$?" -eq 0 ] if [ "$?" -eq 0 ]; then
then
# If the backup succeeded, remove the previous backup # If the backup succeeded, remove the previous backup
if yunohost backup list | grep --quiet $app_bck-pre-upgrade$old_backup_number if ynh_backup_archive_exists "$app_bck-pre-upgrade$old_backup_number"; then
then
# Remove the previous backup only if it exists # Remove the previous backup only if it exists
yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null yunohost backup delete $app_bck-pre-upgrade$old_backup_number >/dev/null
fi fi
else else
ynh_die --message="Backup failed, the upgrade process was aborted." ynh_die --message="Backup failed, the upgrade process was aborted."
@ -450,25 +454,27 @@ ynh_backup_before_upgrade () {
# Restore a previous backup if the upgrade process failed # Restore a previous backup if the upgrade process failed
# #
# usage: # usage: ynh_restore_upgradebackup
#
# Usage in a package script:
# ```
# ynh_backup_before_upgrade # ynh_backup_before_upgrade
# ynh_clean_setup () { # ynh_clean_setup () {
# ynh_restore_upgradebackup # ynh_restore_upgradebackup
# } # }
# ynh_abort_if_errors # ynh_abort_if_errors
# ```
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 2.7.2 or higher.
ynh_restore_upgradebackup () { ynh_restore_upgradebackup() {
ynh_print_err --message="Upgrade failed." ynh_print_err --message="Upgrade failed."
local app_bck=${app//_/-} # Replace all '_' by '-' local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0} NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ] if [ "$NO_BACKUP_UPGRADE" -eq 0 ]; then
then
# Check if an existing backup can be found before removing and restoring the application. # Check if an existing backup can be found before removing and restoring the application.
if yunohost backup list | grep --quiet $app_bck-pre-upgrade$backup_number if ynh_backup_archive_exists "$app_bck-pre-upgrade$backup_number"; then
then
# Remove the application then restore it # Remove the application then restore it
yunohost app remove $app yunohost app remove $app
# Restore the backup # Restore the backup

313
data/helpers.d/config Normal file
View file

@ -0,0 +1,313 @@
#!/bin/bash
_ynh_app_config_get_one() {
local short_setting="$1"
local type="$2"
local bind="$3"
local getter="get__${short_setting}"
# Get value from getter if exists
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
old[$short_setting]="$($getter)"
formats[${short_setting}]="yaml"
elif [[ "$bind" == *"("* ]] && type -t "get__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
old[$short_setting]="$("get__${bind%%(*}" $short_setting $type $bind)"
formats[${short_setting}]="yaml"
elif [[ "$bind" == "null" ]]; then
old[$short_setting]="YNH_NULL"
# Get value from app settings or from another file
elif [[ "$type" == "file" ]]; then
if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
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"
# Get multiline text from settings or from a full file
elif [[ "$type" == "text" ]]; then
if [[ "$bind" == "settings" ]]; then
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
elif [[ "$bind" == *":"* ]]; then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else
old[$short_setting]="$(cat $(echo $bind | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
fi
# Get value from a kind of key/value file
else
local bind_after=""
if [[ "$bind" == "settings" ]]; then
bind=":/etc/yunohost/apps/$app/settings.yml"
fi
local bind_key_="$(echo "$bind" | cut -d: -f1)"
bind_key_=${bind_key_:-$short_setting}
if [[ "$bind_key_" == *">"* ]]; then
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
fi
}
_ynh_app_config_apply_one() {
local short_setting="$1"
local setter="set__${short_setting}"
local bind="${binds[$short_setting]}"
local type="${types[$short_setting]}"
if [ "${changed[$short_setting]}" == "true" ]; then
# Apply setter if exists
if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
$setter
elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"set__${bind%%(*}" $short_setting $type $bind
elif [[ "$bind" == "null" ]]; then
return
# Save in a file
elif [[ "$type" == "file" ]]; then
if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings"
fi
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
if [[ "${!short_setting}" == "" ]]; then
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_secure_remove --file="$bind_file"
ynh_delete_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' removed"
else
ynh_backup_if_checksum_is_different --file="$bind_file"
if [[ "${!short_setting}" != "$bind_file" ]]; then
cp "${!short_setting}" "$bind_file"
fi
ynh_store_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' overwritten with ${!short_setting}"
fi
# Save value in app settings
elif [[ "$bind" == "settings" ]]; then
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
ynh_print_info --message="Configuration key '$short_setting' edited in app settings"
# Save multiline text in a file
elif [[ "$type" == "text" ]]; 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"
fi
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file"
echo "${!short_setting}" >"$bind_file"
ynh_store_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' overwritten with the content provided in question '${short_setting}'"
# Set value into a kind of key/value file
else
local bind_after=""
local bind_key_="$(echo "$bind" | cut -d: -f1)"
bind_key_=${bind_key_:-$short_setting}
if [[ "$bind_key_" == *">"* ]]; then
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
ynh_store_file_checksum --file="$bind_file" --update_only
# We stored the info in settings in order to be able to upgrade the app
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
ynh_print_info --message="Configuration key '$bind_key_' edited into $bind_file"
fi
fi
}
_ynh_app_config_get() {
# From settings
local lines
lines=$(
python3 <<EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
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
IFS=';' read short_setting type bind <<<"$line"
binds[${short_setting}]="$bind"
types[${short_setting}]="$type"
file_hash[${short_setting}]=""
formats[${short_setting}]=""
ynh_app_config_get_one $short_setting $type $bind
done
}
_ynh_app_config_apply() {
for short_setting in "${!old[@]}"; do
ynh_app_config_apply_one $short_setting
done
}
_ynh_app_config_show() {
for short_setting in "${!old[@]}"; do
if [[ "${old[$short_setting]}" != YNH_NULL ]]; then
if [[ "${formats[$short_setting]}" == "yaml" ]]; then
ynh_return "${short_setting}:"
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
else
ynh_return "${short_setting}: "'"'"$(echo "${old[$short_setting]}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\n\n/g')"'"'
fi
fi
done
}
_ynh_app_config_validate() {
# Change detection
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
local nothing_changed=true
local changes_validated=true
for short_setting in "${!old[@]}"; do
changed[$short_setting]=false
if [ -z ${!short_setting+x} ]; then
# Assign the var with the old value in order to allows multiple
# args validation
declare "$short_setting"="${old[$short_setting]}"
continue
fi
if [ ! -z "${file_hash[${short_setting}]}" ]; then
file_hash[old__$short_setting]=""
file_hash[new__$short_setting]=""
if [ -f "${old[$short_setting]}" ]; then
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
if [ -z "${!short_setting}" ]; then
changed[$short_setting]=true
nothing_changed=false
fi
fi
if [ -f "${!short_setting}" ]; then
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]; then
changed[$short_setting]=true
nothing_changed=false
fi
fi
else
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]; then
changed[$short_setting]=true
nothing_changed=false
fi
fi
done
if [[ "$nothing_changed" == "true" ]]; then
ynh_print_info --message="Nothing has changed"
exit 0
fi
# Run validation if something is changed
ynh_script_progression --message="Validating the new configuration..." --weight=1
for short_setting in "${!old[@]}"; do
[[ "${changed[$short_setting]}" == "false" ]] && continue
local result=""
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
result="$(validate__$short_setting)"
elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"validate__${bind%%(*}" $short_setting
fi
if [ -n "$result" ]; then
#
# Return a yaml such as:
#
# validation_errors:
# some_key: "An error message"
# some_other_key: "Another error message"
#
# We use changes_validated to know if this is
# the first validation error
if [[ "$changes_validated" == true ]]; then
ynh_return "validation_errors:"
fi
ynh_return " ${short_setting}: \"$result\""
changes_validated=false
fi
done
# If validation failed, exit the script right now (instead of going into apply)
# Yunohost core will pick up the errors returned via ynh_return previously
if [[ "$changes_validated" == "false" ]]; then
exit 0
fi
}
ynh_app_config_get_one() {
_ynh_app_config_get_one $1 $2 $3
}
ynh_app_config_get() {
_ynh_app_config_get
}
ynh_app_config_show() {
_ynh_app_config_show
}
ynh_app_config_validate() {
_ynh_app_config_validate
}
ynh_app_config_apply_one() {
_ynh_app_config_apply_one $1
}
ynh_app_config_apply() {
_ynh_app_config_apply
}
ynh_app_config_run() {
declare -Ag old=()
declare -Ag changed=()
declare -Ag file_hash=()
declare -Ag binds=()
declare -Ag types=()
declare -Ag formats=()
case $1 in
show)
ynh_app_config_get
ynh_app_config_show
;;
apply)
max_progression=4
ynh_script_progression --message="Reading config panel description and current configuration..."
ynh_app_config_get
ynh_app_config_validate
ynh_script_progression --message="Applying the new configuration..."
ynh_app_config_apply
ynh_script_progression --message="Configuration of $app completed" --last
;;
esac
}

View file

@ -12,15 +12,14 @@
# #
# usage 2: ynh_add_fail2ban_config --use_template [--others_var="list of others variables to replace"] # 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 # | arg: -v, --others_var= - List of others variables to replace separeted by a space for example : 'var_1 var_2 ...'
# | 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
# format and how placeholders are replaced with actual variables. # format and how placeholders are replaced with actual variables.
# #
# Generally your template will look like that by example (for synapse): # Generally your template will look like that by example (for synapse):
# # ```
# f2b_jail.conf: # f2b_jail.conf:
# [__APP__] # [__APP__]
# enabled = true # enabled = true
@ -28,7 +27,8 @@
# filter = __APP__ # filter = __APP__
# logpath = /var/log/__APP__/logfile.log # logpath = /var/log/__APP__/logfile.log
# maxretry = 3 # maxretry = 3
# # ```
# ```
# f2b_filter.conf: # f2b_filter.conf:
# [INCLUDES] # [INCLUDES]
# before = common.conf # before = common.conf
@ -41,14 +41,15 @@
# failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- <HOST> \- \d+ \- Received request\: POST /_matrix/client/r0/login\??<SKIPLINES>%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'<SKIPLINES>%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$ # failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- <HOST> \- \d+ \- Received request\: POST /_matrix/client/r0/login\??<SKIPLINES>%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'<SKIPLINES>%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$
# #
# ignoreregex = # ignoreregex =
# ```
# #
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# #
# Note about the "failregex" option: # Note about the "failregex" option:
# regex to match the password failure messages in the logfile. The #
# host must be matched by a group named "host". The tag "<HOST>" can # regex to match the password failure messages in the logfile. The host must be
# be used for standard IP/hostname matching and is only an alias for # matched by a group named "`host`". The tag "`<HOST>`" can be used for standard
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+) # IP/hostname matching and is only an alias for `(?:::f{4,6}:)?(?P<host>[\w\-.^_]+)`
# #
# You can find some more explainations about how to make a regex here : # 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
@ -56,29 +57,34 @@
# Note that the logfile need to exist before to call this helper !! # 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
# ```
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 4.1.0 or higher.
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=lrmpt 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 ] [[ -z "$others_var" ]] || ynh_print_warn --message="Packagers: using --others_var is unecessary since YunoHost 4.2"
then
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 "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 "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."
echo " echo "
[__APP__] [__APP__]
@ -87,7 +93,7 @@ port = __PORTS__
filter = __APP__ filter = __APP__
logpath = __LOGPATH__ logpath = __LOGPATH__
maxretry = __MAX_RETRY__ maxretry = __MAX_RETRY__
" > ../conf/f2b_jail.conf " >$YNH_APP_BASEDIR/conf/f2b_jail.conf
echo " echo "
[INCLUDES] [INCLUDES]
@ -95,17 +101,16 @@ before = common.conf
[Definition] [Definition]
failregex = __FAILREGEX__ failregex = __FAILREGEX__
ignoreregex = ignoreregex =
" > ../conf/f2b_filter.conf " >$YNH_APP_BASEDIR/conf/f2b_filter.conf
fi fi
ynh_add_config --template="../conf/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="../conf/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"
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")" local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
if [[ -n "$fail2ban_error" ]] if [[ -n "$fail2ban_error" ]]; then
then
ynh_print_err --message="Fail2ban failed to load the jail for $app" ynh_print_err --message="Fail2ban failed to load the jail for $app"
ynh_print_warn --message="${fail2ban_error#*WARNING}" ynh_print_warn --message="${fail2ban_error#*WARNING}"
fi fi
@ -116,8 +121,8 @@ ignoreregex =
# usage: ynh_remove_fail2ban_config # usage: ynh_remove_fail2ban_config
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_remove_fail2ban_config () { ynh_remove_fail2ban_config() {
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf" ynh_secure_remove --file="/etc/fail2ban/jail.d/$app.conf"
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf" ynh_secure_remove --file="/etc/fail2ban/filter.d/$app.conf"
ynh_systemd_action --service_name=fail2ban --action=reload ynh_systemd_action --service_name=fail2ban --action=reload
} }

View file

@ -45,11 +45,10 @@
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2. # e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
# #
# Requires YunoHost version 3.2.2 or higher. # Requires YunoHost version 3.2.2 or higher.
ynh_handle_getopts_args () { ynh_handle_getopts_args() {
# Manage arguments only if there's some provided # Manage arguments only if there's some provided
set +o xtrace # set +x set +o xtrace # set +x
if [ $# -ne 0 ] if [ $# -ne 0 ]; then
then
# Store arguments in an array to keep each argument separated # Store arguments in an array to keep each argument separated
local arguments=("$@") local arguments=("$@")
@ -58,14 +57,12 @@ ynh_handle_getopts_args () {
# ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value) # ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
local getopts_parameters="" local getopts_parameters=""
local option_flag="" local option_flag=""
for option_flag in "${!args_array[@]}" for option_flag in "${!args_array[@]}"; do
do
# Concatenate each option_flags of the array to build the string of arguments for getopts # Concatenate each option_flags of the array to build the string of arguments for getopts
# Will looks like 'abcd' for -a -b -c -d # Will looks like 'abcd' for -a -b -c -d
# If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob) # If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
# Check the last character of the value associate to the option_flag # Check the last character of the value associate to the option_flag
if [ "${args_array[$option_flag]: -1}" = "=" ] if [ "${args_array[$option_flag]: -1}" = "=" ]; then
then
# For an option with additionnal values, add a ':' after the letter for getopts. # For an option with additionnal values, add a ':' after the letter for getopts.
getopts_parameters="${getopts_parameters}${option_flag}:" getopts_parameters="${getopts_parameters}${option_flag}:"
else else
@ -74,8 +71,7 @@ ynh_handle_getopts_args () {
# Check each argument given to the function # Check each argument given to the function
local arg="" local arg=""
# ${#arguments[@]} is the size of the array # ${#arguments[@]} is the size of the array
for arg in `seq 0 $(( ${#arguments[@]} - 1 ))` for arg in $(seq 0 $((${#arguments[@]} - 1))); do
do
# Escape options' values starting with -. Otherwise the - will be considered as another option. # Escape options' values starting with -. Otherwise the - will be considered as another option.
arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}" arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}"
# And replace long option (value of the option_flag) by the short option, the option_flag itself # And replace long option (value of the option_flag) by the short option, the option_flag itself
@ -89,10 +85,9 @@ ynh_handle_getopts_args () {
# Read and parse all the arguments # Read and parse all the arguments
# Use a function here, to use standart arguments $@ and be able to use shift. # Use a function here, to use standart arguments $@ and be able to use shift.
parse_arg () { parse_arg() {
# Read all arguments, until no arguments are left # Read all arguments, until no arguments are left
while [ $# -ne 0 ] while [ $# -ne 0 ]; do
do
# Initialize the index of getopts # Initialize the index of getopts
OPTIND=1 OPTIND=1
# Parse with getopts only if the argument begin by -, that means the argument is an option # Parse with getopts only if the argument begin by -, that means the argument is an option
@ -100,11 +95,9 @@ ynh_handle_getopts_args () {
local parameter="" local parameter=""
getopts ":$getopts_parameters" parameter || true getopts ":$getopts_parameters" parameter || true
if [ "$parameter" = "?" ] if [ "$parameter" = "?" ]; then
then
ynh_die --message="Invalid argument: -${OPTARG:-}" ynh_die --message="Invalid argument: -${OPTARG:-}"
elif [ "$parameter" = ":" ] elif [ "$parameter" = ":" ]; then
then
ynh_die --message="-$OPTARG parameter requires an argument." ynh_die --message="-$OPTARG parameter requires an argument."
else else
local shift_value=1 local shift_value=1
@ -115,8 +108,7 @@ ynh_handle_getopts_args () {
local option_var="${args_array[$parameter]%=}" local option_var="${args_array[$parameter]%=}"
# If this option doesn't take values # If this option doesn't take values
# if there's a '=' at the end of the long option name, this option takes values # if there's a '=' at the end of the long option name, this option takes values
if [ "${args_array[$parameter]: -1}" != "=" ] if [ "${args_array[$parameter]: -1}" != "=" ]; then
then
# 'eval ${option_var}' will use the content of 'option_var' # 'eval ${option_var}' will use the content of 'option_var'
eval ${option_var}=1 eval ${option_var}=1
else else
@ -126,41 +118,35 @@ ynh_handle_getopts_args () {
# If the first argument is longer than 2 characters, # If the first argument is longer than 2 characters,
# There's a value attached to the option, in the same array cell # There's a value attached to the option, in the same array cell
if [ ${#all_args[0]} -gt 2 ] if [ ${#all_args[0]} -gt 2 ]; then
then
# Remove the option and the space, so keep only the value itself. # Remove the option and the space, so keep only the value itself.
all_args[0]="${all_args[0]#-${parameter} }" all_args[0]="${all_args[0]#-${parameter} }"
# At this point, if all_args[0] start with "-", then the argument is not well formed # At this point, if all_args[0] start with "-", then the argument is not well formed
if [ "${all_args[0]:0:1}" == "-" ] if [ "${all_args[0]:0:1}" == "-" ]; then
then
ynh_die --message="Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?" ynh_die --message="Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?"
fi fi
# Reduce the value of shift, because the option has been removed manually # Reduce the value of shift, because the option has been removed manually
shift_value=$(( shift_value - 1 )) shift_value=$((shift_value - 1))
fi fi
# Declare the content of option_var as a variable. # Declare the content of option_var as a variable.
eval ${option_var}="" eval ${option_var}=""
# Then read the array value per value # Then read the array value per value
local i local i
for i in `seq 0 $(( ${#all_args[@]} - 1 ))` for i in $(seq 0 $((${#all_args[@]} - 1))); do
do
# If this argument is an option, end here. # If this argument is an option, end here.
if [ "${all_args[$i]:0:1}" == "-" ] if [ "${all_args[$i]:0:1}" == "-" ]; then
then
# Ignore the first value of the array, which is the option itself # Ignore the first value of the array, which is the option itself
if [ "$i" -ne 0 ]; then if [ "$i" -ne 0 ]; then
break break
fi fi
else else
# Ignore empty parameters # Ignore empty parameters
if [ -n "${all_args[$i]}" ] if [ -n "${all_args[$i]}" ]; then
then
# Else, add this value to this option # Else, add this value to this option
# Each value will be separated by ';' # Each value will be separated by ';'
if [ -n "${!option_var}" ] if [ -n "${!option_var}" ]; then
then
# If there's already another value for this option, add a ; before adding the new value # If there's already another value for this option, add a ; before adding the new value
eval ${option_var}+="\;" eval ${option_var}+="\;"
fi fi
@ -177,7 +163,7 @@ ynh_handle_getopts_args () {
eval ${option_var}+='"${all_args[$i]}"' eval ${option_var}+='"${all_args[$i]}"'
fi fi
shift_value=$(( shift_value + 1 )) shift_value=$((shift_value + 1))
fi fi
done done
fi fi
@ -190,22 +176,21 @@ ynh_handle_getopts_args () {
# LEGACY MODE # LEGACY MODE
# Check if there's getopts arguments # Check if there's getopts arguments
if [ "${arguments[0]:0:1}" != "-" ] if [ "${arguments[0]:0:1}" != "-" ]; then
then
# If not, enter in legacy mode and manage the arguments as positionnal ones.. # If not, enter in legacy mode and manage the arguments as positionnal ones..
# Dot not echo, to prevent to go through a helper output. But print only in the log. # Dot not echo, to prevent to go through a helper output. But print only in the log.
set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x set -x
echo "! Helper used in legacy mode !" >/dev/null
set +x
local i local i
for i in `seq 0 $(( ${#arguments[@]} -1 ))` for i in $(seq 0 $((${#arguments[@]} - 1))); do
do
# Try to use legacy_args as a list of option_flag of the array args_array # Try to use legacy_args as a list of option_flag of the array args_array
# Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order... # Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order...
# Remove all ':' in getopts_parameters # Remove all ':' in getopts_parameters
getopts_parameters=${legacy_args:-${getopts_parameters//:}} getopts_parameters=${legacy_args:-${getopts_parameters//:/}}
# Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument. # Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
option_flag=${getopts_parameters:$i:1} option_flag=${getopts_parameters:$i:1}
if [ -z "$option_flag" ] if [ -z "$option_flag" ]; then
then
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored." ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
continue continue
fi fi

View file

@ -7,13 +7,13 @@
# | arg: -t, --total - Count total RAM+swap # | arg: -t, --total - Count total RAM+swap
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
# | arg: -o, --only_swap - Ignore real RAM, consider only swap # | arg: -o, --only_swap - Ignore real RAM, consider only swap
# | ret: the amount of free ram # | ret: the amount of free ram, in MB (MegaBytes)
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_get_ram () { ynh_get_ram() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=ftso local legacy_args=ftso
local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local -A args_array=([f]=free [t]=total [s]=ignore_swap [o]=only_swap)
local free local free
local total local total
local ignore_swap local ignore_swap
@ -25,41 +25,34 @@ ynh_get_ram () {
free=${free:-0} free=${free:-0}
total=${total:-0} total=${total:-0}
if [ $free -eq $total ] if [ $free -eq $total ]; then
then
ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram" ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram"
ram=0 ram=0
# Use the total amount of ram # Use the total amount of ram
elif [ $free -eq 1 ] elif [ $free -eq 1 ]; then
then
local free_ram=$(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=$(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
local ram=$free_ram_swap local ram=$free_ram_swap
if [ $ignore_swap -eq 1 ] if [ $ignore_swap -eq 1 ]; then
then
# Use only the amount of free ram # Use only the amount of free ram
ram=$free_ram ram=$free_ram
elif [ $only_swap -eq 1 ] elif [ $only_swap -eq 1 ]; then
then
# Use only the amount of free swap # Use only the amount of free swap
ram=$free_swap ram=$free_swap
fi fi
elif [ $total -eq 1 ] elif [ $total -eq 1 ]; then
then
local total_ram=$(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=$(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
if [ $ignore_swap -eq 1 ] if [ $ignore_swap -eq 1 ]; then
then
# Use only the amount of free ram # Use only the amount of free ram
ram=$total_ram ram=$total_ram
elif [ $only_swap -eq 1 ] elif [ $only_swap -eq 1 ]; then
then
# Use only the amount of free swap # Use only the amount of free swap
ram=$total_swap ram=$total_swap
fi fi
@ -70,19 +63,19 @@ 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
# #
# usage: ynh_require_ram --required=RAM required in Mb [--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
# | arg: -t, --total - Count total RAM+swap # | arg: -t, --total - Count total RAM+swap
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
# | arg: -o, --only_swap - Ignore real RAM, consider only swap # | arg: -o, --only_swap - Ignore real RAM, consider only swap
# | exit: Return 1 if the ram is under the requirement, 0 otherwise. # | ret: 1 if the ram is under the requirement, 0 otherwise.
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_require_ram () { ynh_require_ram() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=rftso local legacy_args=rftso
local -A args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local -A args_array=([r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap)
local required local required
local free local free
local total local total
@ -100,8 +93,7 @@ ynh_require_ram () {
local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap) local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap)
if [ $ram -lt $required ] if [ $ram -lt $required ]; then
then
return 1 return 1
else else
return 0 return 0

View file

@ -10,7 +10,7 @@
ynh_die() { ynh_die() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mc local legacy_args=mc
local -A args_array=( [m]=message= [c]=ret_code= ) local -A args_array=([m]=message= [c]=ret_code=)
local message local message
local ret_code local ret_code
# Manage arguments with getopts # Manage arguments with getopts
@ -30,7 +30,7 @@ ynh_die() {
ynh_print_info() { ynh_print_info() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=m local legacy_args=m
local -A args_array=( [m]=message= ) local -A args_array=([m]=message=)
local message local message
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -62,7 +62,7 @@ ynh_no_log() {
# [internal] # [internal]
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_print_log () { ynh_print_log() {
echo -e "${1}" echo -e "${1}"
} }
@ -72,10 +72,10 @@ ynh_print_log () {
# | arg: -m, --message= - The text to print # | arg: -m, --message= - The text to print
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_print_warn () { ynh_print_warn() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=m local legacy_args=m
local -A args_array=( [m]=message= ) local -A args_array=([m]=message=)
local message local message
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -89,10 +89,10 @@ ynh_print_warn () {
# | arg: -m, --message= - The text to print # | arg: -m, --message= - The text to print
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_print_err () { ynh_print_err() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=m local legacy_args=m
local -A args_array=( [m]=message= ) local -A args_array=([m]=message=)
local message local message
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -102,8 +102,7 @@ ynh_print_err () {
# Execute a command and print the result as an error # Execute a command and print the result as an error
# #
# usage: ynh_exec_err your_command # usage: ynh_exec_err "your_command [ | other_command ]"
# usage: ynh_exec_err "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -111,14 +110,13 @@ ynh_print_err () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_exec_err () { ynh_exec_err() {
ynh_print_err "$(eval $@)" ynh_print_err "$(eval $@)"
} }
# Execute a command and print the result as a warning # Execute a command and print the result as a warning
# #
# usage: ynh_exec_warn your_command # usage: ynh_exec_warn "your_command [ | other_command ]"
# usage: ynh_exec_warn "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -126,14 +124,13 @@ ynh_exec_err () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn () { ynh_exec_warn() {
ynh_print_warn "$(eval $@)" ynh_print_warn "$(eval $@)"
} }
# Execute a command and force the result to be printed on stdout # Execute a command and force the result to be printed on stdout
# #
# usage: ynh_exec_warn_less your_command # usage: ynh_exec_warn_less "your_command [ | other_command ]"
# usage: ynh_exec_warn_less "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -141,14 +138,13 @@ ynh_exec_warn () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn_less () { ynh_exec_warn_less() {
eval $@ 2>&1 eval $@ 2>&1
} }
# Execute a command and redirect stdout in /dev/null # Execute a command and redirect stdout in /dev/null
# #
# usage: ynh_exec_quiet your_command # usage: ynh_exec_quiet "your_command [ | other_command ]"
# usage: ynh_exec_quiet "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -156,14 +152,13 @@ ynh_exec_warn_less () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_exec_quiet () { ynh_exec_quiet() {
eval $@ > /dev/null eval $@ >/dev/null
} }
# Execute a command and redirect stdout and stderr in /dev/null # Execute a command and redirect stdout and stderr in /dev/null
# #
# usage: ynh_exec_fully_quiet your_command # usage: ynh_exec_fully_quiet "your_command [ | other_command ]"
# usage: ynh_exec_fully_quiet "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -171,18 +166,20 @@ ynh_exec_quiet () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_exec_fully_quiet () { ynh_exec_fully_quiet() {
eval $@ > /dev/null 2>&1 eval $@ >/dev/null 2>&1
} }
# Remove any logs for all the following commands. # Remove any logs for all the following commands.
# #
# usage: ynh_print_OFF # usage: ynh_print_OFF
# #
# [internal]
#
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging. # WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
# #
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_print_OFF () { ynh_print_OFF() {
exec {BASH_XTRACEFD}>/dev/null exec {BASH_XTRACEFD}>/dev/null
} }
@ -190,11 +187,13 @@ ynh_print_OFF () {
# #
# usage: ynh_print_ON # usage: ynh_print_ON
# #
# [internal]
#
# Requires YunoHost version 3.2.0 or higher. # Requires YunoHost version 3.2.0 or higher.
ynh_print_ON () { ynh_print_ON() {
exec {BASH_XTRACEFD}>&1 exec {BASH_XTRACEFD}>&1
# Print an echo only for the log, to be able to know that ynh_print_ON has been called. # Print an echo only for the log, to be able to know that ynh_print_ON has been called.
echo ynh_print_ON > /dev/null echo ynh_print_ON >/dev/null
} }
# Initial definitions for ynh_script_progression # Initial definitions for ynh_script_progression
@ -219,11 +218,11 @@ base_time=$(date +%s)
# | arg: -l, --last - Use for the last call of the helper, to fill the progression bar. # | arg: -l, --last - Use for the last call of the helper, to fill the progression bar.
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_script_progression () { ynh_script_progression() {
set +o xtrace # set +x set +o xtrace # set +x
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mwtl local legacy_args=mwtl
local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) local -A args_array=([m]=message= [w]=weight= [t]=time [l]=last)
local message local message
local weight local weight
local time local time
@ -237,12 +236,11 @@ ynh_script_progression () {
last=${last:-0} last=${last:-0}
# Get execution time since the last $base_time # Get execution time since the last $base_time
local exec_time=$(( $(date +%s) - $base_time )) local exec_time=$(($(date +%s) - $base_time))
base_time=$(date +%s) base_time=$(date +%s)
# Compute $max_progression (if we didn't already) # Compute $max_progression (if we didn't already)
if [ "$max_progression" = -1 ] if [ "$max_progression" = -1 ]; then
then
# Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented. # Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented.
local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)" local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)"
# Get the number of call with a weight value # Get the number of call with a weight value
@ -254,23 +252,22 @@ ynh_script_progression () {
local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')" local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')"
# Each value will be on a different line. # Each value will be on a different line.
# Remove each 'end of line' and replace it by a '+' to sum the values. # Remove each 'end of line' and replace it by a '+' to sum the values.
local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 )) local weight_values=$(($(echo "$weight_valuesA" "$weight_valuesB" | grep -v -E '^\s*$' | tr '\n' '+' | sed 's/+$/+0/g')))
# max_progression is a total number of calls to this helper. # max_progression is a total number of calls to this helper.
# Less the number of calls with a weight value. # Less the number of calls with a weight value.
# Plus the total of weight values # Plus the total of weight values
max_progression=$(( $helper_calls - $weight_calls + $weight_values )) max_progression=$(($helper_calls - $weight_calls + $weight_values))
fi fi
# Increment each execution of ynh_script_progression in this script by the weight of the previous call. # Increment each execution of ynh_script_progression in this script by the weight of the previous call.
increment_progression=$(( $increment_progression + $previous_weight )) increment_progression=$(($increment_progression + $previous_weight))
# Store the weight of the current call in $previous_weight for next call # Store the weight of the current call in $previous_weight for next call
previous_weight=$weight previous_weight=$weight
# Reduce $increment_progression to the size of the scale # Reduce $increment_progression to the size of the scale
if [ $last -eq 0 ] if [ $last -eq 0 ]; then
then local effective_progression=$(($increment_progression * $progress_scale / $max_progression))
local effective_progression=$(( $increment_progression * $progress_scale / $max_progression ))
# If last is specified, fill immediately the progression_bar # If last is specified, fill immediately the progression_bar
else else
local effective_progression=$progress_scale local effective_progression=$progress_scale
@ -278,19 +275,17 @@ ynh_script_progression () {
# Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task # Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task
# expected_progression is the progression expected after the current task # expected_progression is the progression expected after the current task
local expected_progression="$(( ( $increment_progression + $weight ) * $progress_scale / $max_progression - $effective_progression ))" local expected_progression="$((($increment_progression + $weight) * $progress_scale / $max_progression - $effective_progression))"
if [ $last -eq 1 ] if [ $last -eq 1 ]; then
then
expected_progression=0 expected_progression=0
fi fi
# left_progression is the progression not yet done # left_progression is the progression not yet done
local left_progression="$(( $progress_scale - $effective_progression - $expected_progression ))" local left_progression="$(($progress_scale - $effective_progression - $expected_progression))"
# Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done. # Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done.
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 ] if [ $time -eq 1 ]; then
then
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]" print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
fi fi
@ -298,14 +293,14 @@ ynh_script_progression () {
set -o xtrace # set -x set -o xtrace # set -x
} }
# Return data to the Yunohost core for later processing # Return data to the YunoHost core for later processing
# (to be used by special hooks like app config panel and core diagnosis) # (to be used by special hooks like app config panel and core diagnosis)
# #
# usage: ynh_return somedata # usage: ynh_return somedata
# #
# Requires YunoHost version 3.6.0 or higher. # Requires YunoHost version 3.6.0 or higher.
ynh_return () { ynh_return() {
echo "$1" >> "$YNH_STDRETURN" echo "$1" >>"$YNH_STDRETURN"
} }
# Debugger for app packagers # Debugger for app packagers
@ -315,12 +310,12 @@ ynh_return () {
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script. # | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_debug () { ynh_debug() {
# Disable set xtrace for the helper itself, to not pollute the debug log # Disable set xtrace for the helper itself, to not pollute the debug log
set +o xtrace # set +x set +o xtrace # set +x
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mt local legacy_args=mt
local -A args_array=( [m]=message= [t]=trace= ) local -A args_array=([m]=message= [t]=trace=)
local message local message
local trace local trace
# Manage arguments with getopts # Manage arguments with getopts
@ -330,13 +325,11 @@ ynh_debug () {
message=${message:-} message=${message:-}
trace=${trace:-} trace=${trace:-}
if [ -n "$message" ] if [ -n "$message" ]; then
then
ynh_print_log "[Debug] ${message}" >&2 ynh_print_log "[Debug] ${message}" >&2
fi fi
if [ "$trace" == "1" ] if [ "$trace" == "1" ]; then
then
ynh_debug --message="Enable debugging" ynh_debug --message="Enable debugging"
set +o xtrace # set +x set +o xtrace # set +x
# Get the current file descriptor of xtrace # Get the current file descriptor of xtrace
@ -348,8 +341,7 @@ ynh_debug () {
# Force stdout to stderr # Force stdout to stderr
exec 1>&2 exec 1>&2
fi fi
if [ "$trace" == "0" ] if [ "$trace" == "0" ]; then
then
ynh_debug --message="Disable debugging" ynh_debug --message="Disable debugging"
set +o xtrace # set +x set +o xtrace # set +x
# Put xtrace back to its original fild descriptor # Put xtrace back to its original fild descriptor
@ -363,8 +355,7 @@ ynh_debug () {
# Execute a command and print the result as debug # Execute a command and print the result as debug
# #
# usage: ynh_debug_exec your_command # usage: ynh_debug_exec "your_command [ | other_command ]"
# usage: ynh_debug_exec "your_command | other_command"
# | arg: command - command to execute # | arg: command - command to execute
# #
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
@ -372,6 +363,6 @@ ynh_debug () {
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_debug_exec () { ynh_debug_exec() {
ynh_debug --message="$(eval $@)" ynh_debug --message="$(eval $@)"
} }

View file

@ -7,20 +7,18 @@
# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config. # | 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. # | 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. # If no `--logfile` is provided, `/var/log/$app` will be used as default.
# logfile can be just a directory, or a full path to a logfile : # `logfile` can point to a directory or a file.
# /parentdir/logdir
# /parentdir/logdir/logfile.log
# #
# It's possible to use this helper multiple times, each config will be added to # 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 # the same logrotate config file. Unless you use the option `--non-append`
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
# Requires YunoHost version 3.2.0 or higher for the argument --specific_user # Requires YunoHost version 3.2.0 or higher for the argument `--specific_user`
ynh_use_logrotate () { ynh_use_logrotate() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=lnuya local legacy_args=lnuya
local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append ) 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' # [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
local logfile local logfile
local nonappend local nonappend
@ -32,22 +30,18 @@ ynh_use_logrotate () {
specific_user="${specific_user:-}" specific_user="${specific_user:-}"
# LEGACY CODE - PRE GETOPTS # LEGACY CODE - PRE GETOPTS
if [ $# -gt 0 ] && [ "$1" == "--non-append" ] if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
then
nonappend=1 nonappend=1
# Destroy this argument for the next command. # Destroy this argument for the next command.
shift shift
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ] elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
then
nonappend=1 nonappend=1
fi fi
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ] if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
then
# If the given logfile parameter already exists as a file, or if it ends up with ".log", # 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 # we just want to manage a single file
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ] if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then
then
local logfile=$1 local logfile=$1
# Otherwise we assume we want to manage a directory and all its .log file inside # Otherwise we assume we want to manage a directory and all its .log file inside
else else
@ -60,8 +54,7 @@ ynh_use_logrotate () {
if [ "$nonappend" -eq 1 ]; then if [ "$nonappend" -eq 1 ]; then
customtee="tee" customtee="tee"
fi fi
if [ -n "$logfile" ] if [ -n "$logfile" ]; then
then
if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile 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. local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
fi fi
@ -69,13 +62,12 @@ ynh_use_logrotate () {
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
fi fi
local su_directive="" local su_directive=""
if [[ -n $specific_user ]] if [[ -n $specific_user ]]; then
then
su_directive=" # Run logorotate as specific user - group su_directive=" # Run logorotate as specific user - group
su ${specific_user%/*} ${specific_user#*/}" su ${specific_user%/*} ${specific_user#*/}"
fi fi
cat > ./${app}-logrotate << EOF # Build a config file for logrotate cat >./${app}-logrotate <<EOF # Build a config file for logrotate
$logfile { $logfile {
# Rotate if the logfile exceeds 100Mo # Rotate if the logfile exceeds 100Mo
size 100M size 100M
@ -97,7 +89,12 @@ $logfile {
} }
EOF EOF
mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist 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) 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)
if ynh_user_exists --username="$app"; then
chown $app:$app "$logfile"
chmod o-rwx "$logfile"
fi
} }
# Remove the app's logrotate config. # Remove the app's logrotate config.
@ -105,7 +102,7 @@ EOF
# usage: ynh_remove_logrotate # usage: ynh_remove_logrotate
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_remove_logrotate () { ynh_remove_logrotate() {
if [ -e "/etc/logrotate.d/$app" ]; then if [ -e "/etc/logrotate.d/$app" ]; then
rm "/etc/logrotate.d/$app" rm "/etc/logrotate.d/$app"
fi fi

103
data/helpers.d/multimedia Normal file
View file

@ -0,0 +1,103 @@
#!/bin/bash
readonly MEDIA_GROUP=multimedia
readonly MEDIA_DIRECTORY=/home/yunohost.multimedia
# Initialize the multimedia directory system
#
# usage: ynh_multimedia_build_main_dir
#
# Requires YunoHost version 4.2 or higher.
ynh_multimedia_build_main_dir() {
## Création du groupe multimedia
groupadd -f $MEDIA_GROUP
## Création des dossiers génériques
mkdir -p "$MEDIA_DIRECTORY"
mkdir -p "$MEDIA_DIRECTORY/share"
mkdir -p "$MEDIA_DIRECTORY/share/Music"
mkdir -p "$MEDIA_DIRECTORY/share/Picture"
mkdir -p "$MEDIA_DIRECTORY/share/Video"
mkdir -p "$MEDIA_DIRECTORY/share/eBook"
## Création des dossiers utilisateurs
for user in $(yunohost user list --output-as json | jq -r '.users | keys[]'); do
mkdir -p "$MEDIA_DIRECTORY/$user"
mkdir -p "$MEDIA_DIRECTORY/$user/Music"
mkdir -p "$MEDIA_DIRECTORY/$user/Picture"
mkdir -p "$MEDIA_DIRECTORY/$user/Video"
mkdir -p "$MEDIA_DIRECTORY/$user/eBook"
ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share"
# Création du lien symbolique dans le home de l'utilisateur.
#link will only be created if the home directory of the user exists and if it's located in '/home' folder
local user_home="$(getent passwd $user | cut -d: -f6 | grep '^/home/')"
if [[ -d "$user_home" ]]; then
ln -sfn "$MEDIA_DIRECTORY/$user" "$user_home/Multimedia"
fi
# Propriétaires des dossiers utilisateurs.
chown -R $user "$MEDIA_DIRECTORY/$user"
done
# Default yunohost hooks for post_user_create,delete will take care
# of creating/deleting corresponding multimedia folders when users
# are created/deleted in the future...
## Application des droits étendus sur le dossier multimedia.
# Droit d'écriture pour le groupe et le groupe multimedia en acl et droit de lecture pour other:
setfacl -RnL -m g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY"
# 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"
# 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"
}
# Add a directory in yunohost.multimedia
#
# usage: ynh_multimedia_addfolder --source_dir="source_dir" --dest_dir="dest_dir"
#
# | arg: -s, --source_dir= - Source directory - The real directory which contains your medias.
# | arg: -d, --dest_dir= - Destination directory - The name and the place of the symbolic link, relative to "/home/yunohost.multimedia"
#
# This "directory" will be a symbolic link to a existing directory.
#
# Requires YunoHost version 4.2 or higher.
ynh_multimedia_addfolder() {
# Declare an array to define the options of this helper.
local legacy_args=sd
local -A args_array=([s]=source_dir= [d]=dest_dir=)
local source_dir
local dest_dir
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Ajout d'un lien symbolique vers le dossier à partager
ln -sfn "$source_dir" "$MEDIA_DIRECTORY/$dest_dir"
## Application des droits étendus sur le dossier ajouté
# 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 "$source_dir"
# 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 "$source_dir"
# 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 "$source_dir"
}
# Allow an user to have an write authorisation in multimedia directories
#
# usage: ynh_multimedia_addaccess user_name
#
# | arg: -u, --user_name= - The name of the user which gain this access.
#
# Requires YunoHost version 4.2 or higher.
ynh_multimedia_addaccess() {
# Declare an array to define the options of this helper.
local legacy_args=u
declare -Ar args_array=([u]=user_name=)
local user_name
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
groupadd -f multimedia
usermod -a -G multimedia $user_name
}

View file

@ -1,22 +1,21 @@
#!/bin/bash #!/bin/bash
MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
# Open a connection as a user # Open a connection as a user
# #
# example: ynh_mysql_connect_as --user="user" --password="pass" <<< "UPDATE ...;"
# example: ynh_mysql_connect_as --user="user" --password="pass" < /path/to/file.sql
#
# usage: ynh_mysql_connect_as --user=user --password=password [--database=database] # usage: ynh_mysql_connect_as --user=user --password=password [--database=database]
# | arg: -u, --user= - the user name to connect as # | arg: -u, --user= - the user name to connect as
# | arg: -p, --password= - the user password # | arg: -p, --password= - the user password
# | arg: -d, --database= - the database to connect to # | arg: -d, --database= - the database to connect to
# #
# examples:
# ynh_mysql_connect_as --user="user" --password="pass" <<< "UPDATE ...;"
# ynh_mysql_connect_as --user="user" --password="pass" < /path/to/file.sql
#
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_mysql_connect_as() { ynh_mysql_connect_as() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=upd local legacy_args=upd
local -A args_array=( [u]=user= [p]=password= [d]=database= ) local -A args_array=([u]=user= [p]=password= [d]=database=)
local user local user
local password local password
local database local database
@ -37,20 +36,18 @@ ynh_mysql_connect_as() {
ynh_mysql_execute_as_root() { ynh_mysql_execute_as_root() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=sd local legacy_args=sd
local -A args_array=( [s]=sql= [d]=database= ) local -A args_array=([s]=sql= [d]=database=)
local sql local sql
local database local database
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
database="${database:-}" database="${database:-}"
if [ -n "$database" ] if [ -n "$database" ]; then
then
database="--database=$database" database="--database=$database"
fi fi
ynh_mysql_connect_as --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" \ mysql -B "$database" <<<"$sql"
$database <<< "$sql"
} }
# Execute a command from a file as root user # Execute a command from a file as root user
@ -63,21 +60,18 @@ ynh_mysql_execute_as_root() {
ynh_mysql_execute_file_as_root() { ynh_mysql_execute_file_as_root() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=fd local legacy_args=fd
local -A args_array=( [f]=file= [d]=database= ) local -A args_array=([f]=file= [d]=database=)
local file local file
local database local database
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
database="${database:-}" database="${database:-}"
if [ -n "$database" ] if [ -n "$database" ]; then
then
database="--database=$database" database="--database=$database"
fi fi
mysql -B "$database" <"$file"
ynh_mysql_connect_as --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" \
$database < "$file"
} }
# Create a database and grant optionnaly privilegies to a user # Create a database and grant optionnaly privilegies to a user
@ -96,8 +90,7 @@ ynh_mysql_create_db() {
local sql="CREATE DATABASE ${db};" local sql="CREATE DATABASE ${db};"
# grant all privilegies to user # grant all privilegies to user
if [[ $# -gt 1 ]] if [[ $# -gt 1 ]]; then
then
sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'" sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'"
if [[ -n ${3:-} ]]; then if [[ -n ${3:-} ]]; then
sql+=" IDENTIFIED BY '${3}'" sql+=" IDENTIFIED BY '${3}'"
@ -125,22 +118,22 @@ ynh_mysql_drop_db() {
# Dump a database # Dump a database
# #
# example: ynh_mysql_dump_db --database=roundcube > ./dump.sql
#
# usage: ynh_mysql_dump_db --database=database # usage: ynh_mysql_dump_db --database=database
# | arg: -d, --database= - the database name to dump # | arg: -d, --database= - the database name to dump
# | ret: the mysqldump output # | ret: The mysqldump output
#
# example: ynh_mysql_dump_db --database=roundcube > ./dump.sql
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_mysql_dump_db() { ynh_mysql_dump_db() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=d local legacy_args=d
local -A args_array=( [d]=database= ) local -A args_array=([d]=database=)
local database local database
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
mysqldump --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database" mysqldump --single-transaction --skip-dump-date "$database"
} }
# Create a user # Create a user
@ -161,20 +154,18 @@ ynh_mysql_create_user() {
# #
# 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
# | exit: Return 1 if the user doesn't exist, 0 otherwise. # | ret: 0 if the user exists, 1 otherwise.
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_mysql_user_exists() ynh_mysql_user_exists() {
{
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=u local legacy_args=u
local -A args_array=( [u]=user= ) local -A args_array=([u]=user=)
local user local user
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]] if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]]; then
then
return 1 return 1
else else
return 0 return 0
@ -200,26 +191,27 @@ ynh_mysql_drop_user() {
# | arg: -n, --db_name= - Name of the database # | arg: -n, --db_name= - Name of the database
# | arg: -p, --db_pwd= - Password of the database. If not provided, a password will be generated # | arg: -p, --db_pwd= - Password of the database. If not provided, a password will be generated
# #
# After executing this helper, the password of the created database will be available in $db_pwd # After executing this helper, the password of the created database will be available in `$db_pwd`
# It will also be stored as "mysqlpwd" into the app settings. # It will also be stored as "`mysqlpwd`" into the app settings.
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_mysql_setup_db () { ynh_mysql_setup_db() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=unp local legacy_args=unp
local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= ) local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=)
local db_user local db_user
local db_name local db_name
db_pwd="" db_pwd=""
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local new_db_pwd=$(ynh_string_random) # Generate a random password # Generate a random password
local new_db_pwd=$(ynh_string_random)
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd # If $db_pwd is not provided, use new_db_pwd instead for db_pwd
db_pwd="${db_pwd:-$new_db_pwd}" db_pwd="${db_pwd:-$new_db_pwd}"
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd"
ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd # Store the password in the app's config ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd
} }
# Remove a database if it exists, and the associated user # Remove a database if it exists, and the associated user
@ -229,19 +221,17 @@ ynh_mysql_setup_db () {
# | arg: -n, --db_name= - Name of the database # | arg: -n, --db_name= - Name of the database
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_mysql_remove_db () { ynh_mysql_remove_db() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=un local legacy_args=un
local -A args_array=( [u]=db_user= [n]=db_name= ) local -Ar args_array=([u]=db_user= [n]=db_name=)
local db_user local db_user
local db_name local db_name
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE) if mysqlshow | grep -q "^| $db_name "; then
if mysqlshow --user=root --password=$mysql_root_password | grep --quiet "^| $db_name" ynh_mysql_drop_db $db_name
then # Check if the database exists
ynh_mysql_drop_db $db_name # Remove the database
else else
ynh_print_warn --message="Database $db_name not found" ynh_print_warn --message="Database $db_name not found"
fi fi

View file

@ -2,55 +2,56 @@
# Find a free port and return it # Find a free port and return it
# #
# example: port=$(ynh_find_port --port=8080)
#
# 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
# #
# example: port=$(ynh_find_port --port=8080)
#
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_find_port () { ynh_find_port() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=port= ) local -A args_array=([p]=port=)
local port local port
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port." test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
while ! ynh_port_available --port=$port while ! ynh_port_available --port=$port; do
do port=$((port + 1))
port=$((port+1)) # Else, pass to next port
done done
echo $port echo $port
} }
# Test if a port is available # Test if a port is available
# #
# example: ynh_port_available --port=1234 || ynh_die "Port 1234 is needs to be available for this app"
#
# usage: ynh_find_port --port=XYZ # usage: ynh_find_port --port=XYZ
# | arg: -p, --port= - port to check # | arg: -p, --port= - port to check
# | exit: Return 1 if the port is already used by another process. # | ret: 0 if the port is available, 1 if it is already used by another process.
#
# example: ynh_port_available --port=1234 || ynh_die --message="Port 1234 is needs to be available for this app"
# #
# Requires YunoHost version 3.8.0 or higher. # Requires YunoHost version 3.8.0 or higher.
ynh_port_available () { ynh_port_available() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=port= ) local -A args_array=([p]=port=)
local port local port
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$" # Check if the port is free # Check if the port is free
then if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$"; then
return 1
# This is to cover (most) case where an app is using a port yet ain't currently using it for some reason (typically service ain't up)
elif grep -q "port: '$port'" /etc/yunohost/apps/*/settings.yml; then
return 1 return 1
else else
return 0 return 0
fi fi
} }
# Validate an IP address # Validate an IP address
# #
# [internal] # [internal]
@ -61,13 +62,12 @@ ynh_port_available () {
# example: ynh_validate_ip 4 111.222.333.444 # example: ynh_validate_ip 4 111.222.333.444
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip() ynh_validate_ip() {
{
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298 # http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=fi local legacy_args=fi
local -A args_array=( [f]=family= [i]=ip_address= ) local -A args_array=([f]=family= [i]=ip_address=)
local family local family
local ip_address local ip_address
# Manage arguments with getopts # Manage arguments with getopts
@ -75,7 +75,7 @@ ynh_validate_ip()
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1 [ "$family" == "4" ] || [ "$family" == "6" ] || return 1
python /dev/stdin << EOF python3 /dev/stdin <<EOF
import socket import socket
import sys import sys
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 } family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
@ -89,18 +89,17 @@ EOF
# Validate an IPv4 address # Validate an IPv4 address
# #
# example: ynh_validate_ip4 111.222.333.444
#
# usage: ynh_validate_ip4 --ip_address=ip_address # usage: ynh_validate_ip4 --ip_address=ip_address
# | arg: -i, --ip_address= - the ipv4 address to check # | arg: -i, --ip_address= - the ipv4 address to check
# | ret: 0 for valid ipv4 addresses, 1 otherwise # | ret: 0 for valid ipv4 addresses, 1 otherwise
# #
# example: ynh_validate_ip4 111.222.333.444
#
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip4() ynh_validate_ip4() {
{
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=i local legacy_args=i
local -A args_array=( [i]=ip_address= ) local -A args_array=([i]=ip_address=)
local ip_address local ip_address
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -108,21 +107,19 @@ ynh_validate_ip4()
ynh_validate_ip --family=4 --ip_address=$ip_address ynh_validate_ip --family=4 --ip_address=$ip_address
} }
# Validate an IPv6 address # Validate an IPv6 address
# #
# example: ynh_validate_ip6 2000:dead:beef::1
#
# usage: ynh_validate_ip6 --ip_address=ip_address # usage: ynh_validate_ip6 --ip_address=ip_address
# | arg: -i, --ip_address= - the ipv6 address to check # | arg: -i, --ip_address= - the ipv6 address to check
# | ret: 0 for valid ipv6 addresses, 1 otherwise # | ret: 0 for valid ipv6 addresses, 1 otherwise
# #
# example: ynh_validate_ip6 2000:dead:beef::1
#
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip6() ynh_validate_ip6() {
{
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=i local legacy_args=i
local -A args_array=( [i]=ip_address= ) local -A args_array=([i]=ip_address=)
local ip_address local ip_address
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"

View file

@ -4,31 +4,29 @@
# #
# usage: ynh_add_nginx_config # usage: ynh_add_nginx_config
# #
# This will use a template in ../conf/nginx.conf # This will use a template in `../conf/nginx.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
# format and how placeholders are replaced with actual variables. # format and how placeholders are replaced with actual variables.
# #
# Additionally, ynh_add_nginx_config will replace: # Additionally, ynh_add_nginx_config will replace:
# - #sub_path_only by empty string if path_url is not '/' # - `#sub_path_only` by empty string if `path_url` is not `'/'`
# - #root_path_only by empty string if path_url *is* '/' # - `#root_path_only` by empty string if `path_url` *is* `'/'`
# #
# This allows to enable/disable specific behaviors dependenging on the install # This allows to enable/disable specific behaviors dependenging on the install
# location # location
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 4.1.0 or higher.
ynh_add_nginx_config () { ynh_add_nginx_config() {
local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
if [ "${path_url:-}" != "/" ] if [ "${path_url:-}" != "/" ]; then
then ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="../conf/nginx.conf"
else else
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="../conf/nginx.conf" ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
fi fi
ynh_add_config --template="../conf/nginx.conf" --destination="$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
} }
@ -38,7 +36,7 @@ ynh_add_nginx_config () {
# usage: ynh_remove_nginx_config # usage: ynh_remove_nginx_config
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 2.7.2 or higher.
ynh_remove_nginx_config () { 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
} }

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
n_version=7.0.0 n_version=7.5.0
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.
@ -13,26 +13,30 @@ export N_PREFIX="$n_install_dir"
# usage: ynh_install_n # usage: ynh_install_n
# #
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_install_n () { ynh_install_n() {
ynh_print_info --message="Installation of N - Node.js version management" ynh_print_info --message="Installation of N - Node.js version management"
# Build an app.src for n # Build an app.src for n
mkdir --parents "../conf"
echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz
SOURCE_SUM=2933855140f980fc6d1d6103ea07cd4d915b17dea5e17e43921330ea89978b5b" > "../conf/n.src" SOURCE_SUM=d4da7ea91f680de0c9b5876e097e2a793e8234fcd0f7ca87a0599b925be087a3" >"$YNH_APP_BASEDIR/conf/n.src"
# Download and extract n # Download and extract n
ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
# Install n # Install n
(cd "$n_install_dir/git" (
PREFIX=$N_PREFIX make install 2>&1) 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.
# #
# ynh_use_nodejs has to be used in any app scripts before using node for the first time. # usage: ynh_use_nodejs
#
# `ynh_use_nodejs` has to be used in any app scripts before using node for the first time.
# This helper will provide alias and variables to use in your scripts. # This helper will provide alias and variables to use in your scripts.
# #
# To use npm or node, use the alias `ynh_npm` and `ynh_node` # To use npm or node, use the alias `ynh_npm` and `ynh_node`.
# Those alias will use the correct version installed for the app #
# Those alias will use the correct version installed for the app.
# For example: use `ynh_npm install` instead of `npm install` # For example: use `ynh_npm install` instead of `npm install`
# #
# With `sudo` or `ynh_exec_as`, use instead the fallback variables `$ynh_npm` and `$ynh_node` # With `sudo` or `ynh_exec_as`, use instead the fallback variables `$ynh_npm` and `$ynh_node`
@ -40,7 +44,7 @@ SOURCE_SUM=2933855140f980fc6d1d6103ea07cd4d915b17dea5e17e43921330ea89978b5b" > "
# Exemple: `ynh_exec_as $app $ynh_node_load_PATH $ynh_npm install` # Exemple: `ynh_exec_as $app $ynh_node_load_PATH $ynh_npm install`
# #
# $PATH contains the path of the requested version of node. # $PATH contains the path of the requested version of node.
# However, $PATH is duplicated into $node_PATH to outlast any manipulation of $PATH # However, $PATH is duplicated into $node_PATH to outlast any manipulation of `$PATH`
# You can use the variable `$ynh_node_load_PATH` to quickly load your node version # You can use the variable `$ynh_node_load_PATH` to quickly load your node version
# in $PATH for an usage into a separate script. # in $PATH for an usage into a separate script.
# Exemple: $ynh_node_load_PATH $final_path/script_that_use_npm.sh` # Exemple: $ynh_node_load_PATH $final_path/script_that_use_npm.sh`
@ -48,13 +52,17 @@ SOURCE_SUM=2933855140f980fc6d1d6103ea07cd4d915b17dea5e17e43921330ea89978b5b" > "
# #
# Finally, to start a nodejs service with the correct version, 2 solutions # Finally, to start a nodejs service with the correct version, 2 solutions
# Either the app is dependent of node or npm, but does not called it directly. # Either the app is dependent of node or npm, but does not called it directly.
# In such situation, you need to load PATH # In such situation, you need to load PATH :
# `Environment="__NODE_ENV_PATH__"` # ```
# `ExecStart=__FINALPATH__/my_app` # Environment="__NODE_ENV_PATH__"
# You will replace __NODE_ENV_PATH__ with $ynh_node_load_PATH # ExecStart=__FINALPATH__/my_app
# ```
# You will replace __NODE_ENV_PATH__ with $ynh_node_load_PATH.
# #
# Or node start the app directly, then you don't need to load the PATH variable # Or node start the app directly, then you don't need to load the PATH variable
# `ExecStart=__YNH_NODE__ my_app run` # ```
# ExecStart=__YNH_NODE__ my_app run
# ```
# You will replace __YNH_NODE__ with $ynh_node # You will replace __YNH_NODE__ with $ynh_node
# #
# #
@ -62,10 +70,8 @@ SOURCE_SUM=2933855140f980fc6d1d6103ea07cd4d915b17dea5e17e43921330ea89978b5b" > "
# - $nodejs_path: The absolute path to node binaries for the chosen version. # - $nodejs_path: The absolute path to node binaries for the chosen version.
# - $nodejs_version: Just the version number of node for this app. Stored as 'nodejs_version' in settings.yml. # - $nodejs_version: Just the version number of node for this app. Stored as 'nodejs_version' in settings.yml.
# #
# usage: ynh_use_nodejs
#
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_use_nodejs () { ynh_use_nodejs() {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
# Get the absolute path of this version of node # Get the absolute path of this version of node
@ -88,6 +94,8 @@ ynh_use_nodejs () {
node_PATH="$PATH" node_PATH="$PATH"
# Create an alias to easily load the PATH # Create an alias to easily load the PATH
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...
ynh_node_load_path="PATH=$node_PATH"
} }
# Install a specific version of nodejs # Install a specific version of nodejs
@ -97,18 +105,18 @@ ynh_use_nodejs () {
# 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). The crontab will then handle the update of minor versions when needed. # | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). 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
# #
# Refer to ynh_use_nodejs for more information about available commands and variables # Refer to `ynh_use_nodejs` for more information about available commands and variables
# #
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_install_nodejs () { ynh_install_nodejs() {
# Use n, https://github.com/tj/n to manage the nodejs versions # Use n, https://github.com/tj/n to manage the nodejs versions
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=n local legacy_args=n
local -A args_array=( [n]=nodejs_version= ) local -A args_array=([n]=nodejs_version=)
local nodejs_version local nodejs_version
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -126,11 +134,9 @@ ynh_install_nodejs () {
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
# If n is not previously setup, install it # If n is not previously setup, install it
if ! $n_install_dir/bin/n --version > /dev/null 2>&1 if ! $n_install_dir/bin/n --version >/dev/null 2>&1; then
then
ynh_install_n ynh_install_n
elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version; then
then
ynh_install_n ynh_install_n
fi fi
@ -146,8 +152,7 @@ ynh_install_nodejs () {
# Install the requested version of nodejs # Install the requested version of nodejs
uname=$(uname --machine) uname=$(uname --machine)
if [[ $uname =~ aarch64 || $uname =~ arm64 ]] if [[ $uname =~ aarch64 || $uname =~ arm64 ]]; then
then
n $nodejs_version --arch=arm64 n $nodejs_version --arch=arm64
else else
n $nodejs_version n $nodejs_version
@ -158,8 +163,7 @@ ynh_install_nodejs () {
real_nodejs_version=$(basename $real_nodejs_version) real_nodejs_version=$(basename $real_nodejs_version)
# Create a symbolic link for this major version if the file doesn't already exist # Create a symbolic link for this major version if the file doesn't already exist
if [ ! -e "$node_version_path/$nodejs_version" ] if [ ! -e "$node_version_path/$nodejs_version" ]; then
then
ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version
fi fi
@ -177,28 +181,26 @@ ynh_install_nodejs () {
# Remove the version of node used by the app. # Remove the version of node used by the app.
# #
# This helper will check if another app uses the same version of node,
# if not, this version of node will be removed.
# If no other app uses node, n will be also removed.
#
# usage: ynh_remove_nodejs # usage: ynh_remove_nodejs
# #
# This helper will check if another app uses the same version of node.
# - If not, this version of node will be removed.
# - If no other app uses node, n will be also removed.
#
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_remove_nodejs () { 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 "/$YNH_APP_INSTANCE_NAME:$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" if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"; then
then
$n_install_dir/bin/n rm $nodejs_version $n_install_dir/bin/n rm $nodejs_version
fi fi
# If no other app uses n, remove n # If no other app uses n, remove n
if [ ! -s "$n_install_dir/ynh_app_version" ] if [ ! -s "$n_install_dir/ynh_app_version" ]; then
then
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
@ -215,9 +217,9 @@ ynh_remove_nodejs () {
# usage: ynh_cron_upgrade_node # usage: ynh_cron_upgrade_node
# #
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_cron_upgrade_node () { ynh_cron_upgrade_node() {
# Build the update script # Build the update script
cat > "$n_install_dir/node_update.sh" << EOF cat >"$n_install_dir/node_update.sh" <<EOF
#!/bin/bash #!/bin/bash
version_path="$node_version_path" version_path="$node_version_path"
@ -253,7 +255,7 @@ EOF
chmod +x "$n_install_dir/node_update.sh" chmod +x "$n_install_dir/node_update.sh"
# Build the cronjob # Build the cronjob
cat > "/etc/cron.daily/node_update" << EOF cat >"/etc/cron.daily/node_update" <<EOF
#!/bin/bash #!/bin/bash
$n_install_dir/node_update.sh >> $n_install_dir/node_update.log $n_install_dir/node_update.sh >> $n_install_dir/node_update.log

View file

@ -2,15 +2,17 @@
# Create a new permission for the app # Create a new permission for the app
# #
# example 1: ynh_permission_create --permission=admin --url=/admin --additional_urls=domain.tld/admin /superadmin --allowed=alice bob \ # Example 1: `ynh_permission_create --permission=admin --url=/admin --additional_urls=domain.tld/admin /superadmin --allowed=alice bob \
# --label="My app admin" --show_tile=true # --label="My app admin" --show_tile=true`
# #
# This example will create a new permission permission with this following effect: # This example will create a new permission permission with this following effect:
# - A tile named "My app admin" in the SSO will be available for the users alice and bob. This tile will point to the relative url '/admin'. # - A tile named "My app admin" in the SSO will be available for the users alice and bob. This tile will point to the relative url '/admin'.
# - Only the user alice and bob will have the access to theses following url: /admin, domain.tld/admin, /superadmin # - Only the user alice and bob will have the access to theses following url: /admin, domain.tld/admin, /superadmin
# #
# #
# example 2: ynh_permission_create --permission=api --url=domain.tld/api --auth_header=false --allowed=visitors \ # Example 2:
#
# ynh_permission_create --permission=api --url=domain.tld/api --auth_header=false --allowed=visitors \
# --label="MyApp API" --protected=true # --label="MyApp API" --protected=true
# #
# This example will create a new protected permission. So the admin won't be able to add/remove the visitors group of this permission. # This example will create a new protected permission. So the admin won't be able to add/remove the visitors group of this permission.
@ -25,19 +27,14 @@
# usage: ynh_permission_create --permission="permission" [--url="url"] [--additional_urls="second-url" [ "third-url" ]] [--auth_header=true|false] # usage: ynh_permission_create --permission="permission" [--url="url"] [--additional_urls="second-url" [ "third-url" ]] [--auth_header=true|false]
# [--allowed=group1 [ group2 ]] [--label="label"] [--show_tile=true|false] # [--allowed=group1 [ group2 ]] [--label="label"] [--show_tile=true|false]
# [--protected=true|false] # [--protected=true|false]
# | arg: -p, permission= - the name for the permission (by default a permission named "main" already exist) # | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist)
# | arg: -u, url= - (optional) URL for which access will be allowed/forbidden. # | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden. Note that if 'show_tile' is enabled, this URL will be the URL of the tile.
# | Not that if 'show_tile' is enabled, this URL will be the URL of the tile. # | arg: -A, --additional_urls= - (optional) List of additional URL for which access will be allowed/forbidden
# | arg: -A, additional_urls= - (optional) List of additional URL for which access will be allowed/forbidden # | arg: -h, --auth_header= - (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application. Default is true
# | arg: -h, auth_header= - (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application. Default is true # | arg: -a, --allowed= - (optional) A list of group/user to allow for the permission
# | arg: -a, allowed= - (optional) A list of group/user to allow for the permission # | arg: -l, --label= - (optional) Define a name for the permission. This label will be shown on the SSO and in the admin. Default is "APP_LABEL (permission name)".
# | arg: -l, label= - (optional) Define a name for the permission. This label will be shown on the SSO and in the admin. # | arg: -t, --show_tile= - (optional) Define if a tile will be shown in the SSO. If yes the name of the tile will be the 'label' parameter. Defaults to false for the permission different than 'main'.
# | Default is "APP_LABEL (permission name)". # | arg: -P, --protected= - (optional) Define if this permission is protected. If it is protected the administrator won't be able to add or remove the visitors group of this permission. Defaults to 'false'.
# | arg: -t, show_tile= - (optional) Define if a tile will be shown in the SSO. If yes the name of the tile will be the 'label' parameter.
# | Default is false (for the permission different than 'main').
# | arg: -P, protected= - (optional) Define if this permission is protected. If it is protected the administrator
# | won't be able to add or remove the visitors group of this permission.
# | By default it's 'false'
# #
# If provided, 'url' or 'additional_urls' is assumed to be relative to the app domain/path if they # If provided, 'url' or 'additional_urls' is assumed to be relative to the app domain/path if they
# start with '/'. For example: # start with '/'. For example:
@ -69,7 +66,7 @@
ynh_permission_create() { ynh_permission_create() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=puAhaltP local legacy_args=puAhaltP
local -A args_array=( [p]=permission= [u]=url= [A]=additional_urls= [h]=auth_header= [a]=allowed= [l]=label= [t]=show_tile= [P]=protected= ) local -A args_array=([p]=permission= [u]=url= [A]=additional_urls= [h]=auth_header= [a]=allowed= [l]=label= [t]=show_tile= [P]=protected=)
local permission local permission
local url local url
local additional_urls local additional_urls
@ -87,13 +84,11 @@ ynh_permission_create() {
show_tile=${show_tile:-} show_tile=${show_tile:-}
protected=${protected:-} protected=${protected:-}
if [[ -n $url ]] if [[ -n $url ]]; then
then
url=",url='$url'" url=",url='$url'"
fi fi
if [[ -n $additional_urls ]] if [[ -n $additional_urls ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# By example: # By example:
@ -103,18 +98,15 @@ ynh_permission_create() {
additional_urls=",additional_urls=['${additional_urls//;/\',\'}']" additional_urls=",additional_urls=['${additional_urls//;/\',\'}']"
fi fi
if [[ -n $auth_header ]] if [[ -n $auth_header ]]; then
then if [ $auth_header == "true" ]; then
if [ $auth_header == "true" ]
then
auth_header=",auth_header=True" auth_header=",auth_header=True"
else else
auth_header=",auth_header=False" auth_header=",auth_header=False"
fi fi
fi fi
if [[ -n $allowed ]] if [[ -n $allowed ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# By example: # By example:
@ -130,20 +122,16 @@ ynh_permission_create() {
label=",label='$permission'" label=",label='$permission'"
fi fi
if [[ -n ${show_tile:-} ]] if [[ -n ${show_tile:-} ]]; then
then if [ $show_tile == "true" ]; then
if [ $show_tile == "true" ]
then
show_tile=",show_tile=True" show_tile=",show_tile=True"
else else
show_tile=",show_tile=False" show_tile=",show_tile=False"
fi fi
fi fi
if [[ -n ${protected:-} ]] if [[ -n ${protected:-} ]]; then
then if [ $protected == "true" ]; then
if [ $protected == "true" ]
then
protected=",protected=True" protected=",protected=True"
else else
protected=",protected=False" protected=",protected=False"
@ -164,7 +152,7 @@ ynh_permission_create() {
ynh_permission_delete() { ynh_permission_delete() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=permission= ) local -A args_array=([p]=permission=)
local permission local permission
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -181,30 +169,30 @@ ynh_permission_delete() {
ynh_permission_exists() { ynh_permission_exists() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=permission= ) local -A args_array=([p]=permission=)
local permission local permission
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
yunohost user permission list --short | grep --word-regexp --quiet "$app.$permission" yunohost user permission list "$app" --output-as json --quiet \
| jq -e --arg perm "$app.$permission" '.permissions[$perm]' >/dev/null
} }
# Redefine the url associated to a permission # Redefine the url associated to a permission
# #
# usage: ynh_permission_url --permission "permission" [--url="url"] [--add_url="new-url" [ "other-new-url" ]] [--remove_url="old-url" [ "other-old-url" ]] # usage: ynh_permission_url --permission "permission" [--url="url"] [--add_url="new-url" [ "other-new-url" ]] [--remove_url="old-url" [ "other-old-url" ]]
# [--auth_header=true|false] [--clear_urls] # [--auth_header=true|false] [--clear_urls]
# | arg: -p, permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) # | arg: -p, --permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
# | arg: -u, url= - (optional) URL for which access will be allowed/forbidden. # | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden. Note that if you want to remove url you can pass an empty sting as arguments ("").
# | Note that if you want to remove url you can pass an empty sting as arguments (""). # | arg: -a, --add_url= - (optional) List of additional url to add for which access will be allowed/forbidden.
# | arg: -a, add_url= - (optional) List of additional url to add for which access will be allowed/forbidden. # | arg: -r, --remove_url= - (optional) List of additional url to remove for which access will be allowed/forbidden
# | arg: -r, remove_url= - (optional) List of additional url to remove for which access will be allowed/forbidden # | arg: -h, --auth_header= - (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application
# | arg: -h, auth_header= - (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application # | arg: -c, --clear_urls - (optional) Clean all urls (url and additional_urls)
# | arg: -c, clear_urls - (optional) Clean all urls (url and additional_urls)
# #
# Requires YunoHost version 3.7.0 or higher. # Requires YunoHost version 3.7.0 or higher.
ynh_permission_url() { ynh_permission_url() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=puarhc local legacy_args=puarhc
local -A args_array=( [p]=permission= [u]=url= [a]=add_url= [r]=remove_url= [h]=auth_header= [c]=clear_urls ) local -A args_array=([p]=permission= [u]=url= [a]=add_url= [r]=remove_url= [h]=auth_header= [c]=clear_urls)
local permission local permission
local url local url
local add_url local add_url
@ -218,13 +206,11 @@ ynh_permission_url() {
auth_header=${auth_header:-} auth_header=${auth_header:-}
clear_urls=${clear_urls:-} clear_urls=${clear_urls:-}
if [[ -n $url ]] if [[ -n $url ]]; then
then
url=",url='$url'" url=",url='$url'"
fi fi
if [[ -n $add_url ]] if [[ -n $add_url ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# For example: # For example:
@ -234,8 +220,7 @@ ynh_permission_url() {
add_url=",add_url=['${add_url//;/\',\'}']" add_url=",add_url=['${add_url//;/\',\'}']"
fi fi
if [[ -n $remove_url ]] if [[ -n $remove_url ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# For example: # For example:
@ -245,42 +230,37 @@ ynh_permission_url() {
remove_url=",remove_url=['${remove_url//;/\',\'}']" remove_url=",remove_url=['${remove_url//;/\',\'}']"
fi fi
if [[ -n $auth_header ]] if [[ -n $auth_header ]]; then
then if [ $auth_header == "true" ]; then
if [ $auth_header == "true" ]
then
auth_header=",auth_header=True" auth_header=",auth_header=True"
else else
auth_header=",auth_header=False" auth_header=",auth_header=False"
fi fi
fi fi
if [[ -n $clear_urls ]] && [ $clear_urls -eq 1 ] if [[ -n $clear_urls ]] && [ $clear_urls -eq 1 ]; then
then
clear_urls=",clear_urls=True" clear_urls=",clear_urls=True"
fi fi
yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission' $url $add_url $remove_url $auth_header $clear_urls)" yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission' $url $add_url $remove_url $auth_header $clear_urls)"
} }
# Update a permission for the app # Update a permission for the app
# #
# usage: ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]] # usage: ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]]
# [--label="label"] [--show_tile=true|false] [--protected=true|false] # [--label="label"] [--show_tile=true|false] [--protected=true|false]
# | arg: -p, permission= - the name for the permission (by default a permission named "main" already exist) # | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist)
# | arg: -a, add= - the list of group or users to enable add to the permission # | arg: -a, --add= - the list of group or users to enable add to the permission
# | arg: -r, remove= - the list of group or users to remove from the permission # | arg: -r, --remove= - the list of group or users to remove from the permission
# | arg: -l, label= - (optional) Define a name for the permission. This label will be shown on the SSO and in the admin. # | arg: -l, --label= - (optional) Define a name for the permission. This label will be shown on the SSO and in the admin.
# | arg: -t, show_tile= - (optional) Define if a tile will be shown in the SSO # | arg: -t, --show_tile= - (optional) Define if a tile will be shown in the SSO
# | arg: -P, protected= - (optional) Define if this permission is protected. If it is protected the administrator # | arg: -P, --protected= - (optional) Define if this permission is protected. If it is protected the administrator won't be able to add or remove the visitors group of this permission.
# | won't be able to add or remove the visitors group of this permission.
# #
# Requires YunoHost version 3.7.0 or higher. # Requires YunoHost version 3.7.0 or higher.
ynh_permission_update() { ynh_permission_update() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=parltP local legacy_args=parltP
local -A args_array=( [p]=permission= [a]=add= [r]=remove= [l]=label= [t]=show_tile= [P]=protected= ) local -A args_array=([p]=permission= [a]=add= [r]=remove= [l]=label= [t]=show_tile= [P]=protected=)
local permission local permission
local add local add
local remove local remove
@ -294,8 +274,7 @@ ynh_permission_update() {
show_tile=${show_tile:-} show_tile=${show_tile:-}
protected=${protected:-} protected=${protected:-}
if [[ -n $add ]] if [[ -n $add ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# For example: # For example:
@ -304,8 +283,7 @@ ynh_permission_update() {
# add=['alice', 'bob'] # add=['alice', 'bob']
add=",add=['${add//';'/"','"}']" add=",add=['${add//';'/"','"}']"
fi fi
if [[ -n $remove ]] if [[ -n $remove ]]; then
then
# Convert a list from getopts to python list # Convert a list from getopts to python list
# Note that getopts separate the args with ';' # Note that getopts separate the args with ';'
# For example: # For example:
@ -315,15 +293,12 @@ ynh_permission_update() {
remove=",remove=['${remove//';'/"','"}']" remove=",remove=['${remove//';'/"','"}']"
fi fi
if [[ -n $label ]] if [[ -n $label ]]; then
then
label=",label='$label'" label=",label='$label'"
fi fi
if [[ -n $show_tile ]] if [[ -n $show_tile ]]; then
then if [ $show_tile == "true" ]; then
if [ $show_tile == "true" ]
then
show_tile=",show_tile=True" show_tile=",show_tile=True"
else else
show_tile=",show_tile=False" show_tile=",show_tile=False"
@ -331,8 +306,7 @@ ynh_permission_update() {
fi fi
if [[ -n $protected ]]; then if [[ -n $protected ]]; then
if [ $protected == "true" ] if [ $protected == "true" ]; then
then
protected=",protected=True" protected=",protected=True"
else else
protected=",protected=False" protected=",protected=False"
@ -355,18 +329,25 @@ ynh_permission_update() {
ynh_permission_has_user() { ynh_permission_has_user() {
local legacy_args=pu local legacy_args=pu
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local -A args_array=( [p]=permission= [u]=user= ) local -A args_array=([p]=permission= [u]=user=)
local permission local permission
local user local user
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if ! ynh_permission_exists --permission=$permission if ! ynh_permission_exists --permission=$permission; then
then
return 1 return 1
fi fi
yunohost user permission info "$app.$permission" | grep --word-regexp --quiet "$user" # Check both allowed and corresponding_users sections in the json
for section in "allowed" "corresponding_users"; do
if yunohost user permission info "$app.$permission" --output-as json --quiet \
| jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null; then
return 0
fi
done
return 1
} }
# Check if a legacy permissions exist # Check if a legacy permissions exist
@ -375,9 +356,8 @@ ynh_permission_has_user() {
# | exit: Return 1 if the permission doesn't exist, 0 otherwise # | exit: Return 1 if the permission doesn't exist, 0 otherwise
# #
# Requires YunoHost version 4.1.2 or higher. # Requires YunoHost version 4.1.2 or higher.
ynh_legacy_permissions_exists () { ynh_legacy_permissions_exists() {
for permission in "skipped" "unprotected" "protected" for permission in "skipped" "unprotected" "protected"; do
do
if ynh_permission_exists --permission="legacy_${permission}_uris"; then if ynh_permission_exists --permission="legacy_${permission}_uris"; then
return 0 return 0
fi fi
@ -396,9 +376,8 @@ ynh_legacy_permissions_exists () {
# # You can recreate the required permissions here with ynh_permission_create # # You can recreate the required permissions here with ynh_permission_create
# fi # fi
# Requires YunoHost version 4.1.2 or higher. # Requires YunoHost version 4.1.2 or higher.
ynh_legacy_permissions_delete_all () { ynh_legacy_permissions_delete_all() {
for permission in "skipped" "unprotected" "protected" for permission in "skipped" "unprotected" "protected"; do
do
if ynh_permission_exists --permission="legacy_${permission}_uris"; then if ynh_permission_exists --permission="legacy_${permission}_uris"; then
ynh_permission_delete --permission="legacy_${permission}_uris" ynh_permission_delete --permission="legacy_${permission}_uris"
fi fi

View file

@ -55,13 +55,11 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
# RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many # RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many
# children ready to answer. # children ready to answer.
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 4.1.0 or higher.
# Requires YunoHost version 3.5.1 or higher for the argument --phpversion ynh_add_fpm_config() {
# Requires YunoHost version 3.8.1 or higher for the arguments --use_template, --usage, --footprint, --package and --dedicated_service
ynh_add_fpm_config () {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=vtufpd local legacy_args=vtufpd
local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) local -A args_array=([v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
local phpversion local phpversion
local use_template local use_template
local usage local usage
@ -88,8 +86,7 @@ ynh_add_fpm_config () {
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
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ] if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]; then
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"
@ -99,25 +96,21 @@ ynh_add_fpm_config () {
fi fi
# If the requested PHP version is not the default version for YunoHost # If the requested PHP version is not the default version for YunoHost
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]; then
then
# If the argument --package is used, add the packages to ynh_install_php to install them from sury # If the argument --package is used, add the packages to ynh_install_php to install them from sury
if [ -n "$package" ] if [ -n "$package" ]; then
then
local additionnal_packages="--package=$package" local additionnal_packages="--package=$package"
else else
local additionnal_packages="" local additionnal_packages=""
fi fi
# Install this specific version of PHP. # Install this specific version of PHP.
ynh_install_php --phpversion="$phpversion" "$additionnal_packages" ynh_install_php --phpversion="$phpversion" "$additionnal_packages"
elif [ -n "$package" ] elif [ -n "$package" ]; then
then
# Install the additionnal packages from the default repository # Install the additionnal packages from the default repository
ynh_add_app_dependencies --package="$package" ynh_install_app_dependencies "$package"
fi fi
if [ $dedicated_service -eq 1 ] if [ $dedicated_service -eq 1 ]; then
then
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
@ -134,12 +127,10 @@ ynh_add_fpm_config () {
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
# Migrate from mutual PHP service to dedicated one. # Migrate from mutual PHP service to dedicated one.
if [ $dedicated_service -eq 1 ] if [ $dedicated_service -eq 1 ]; then
then
local old_fpm_config_dir="/etc/php/$phpversion/fpm" local old_fpm_config_dir="/etc/php/$phpversion/fpm"
# If a config file exist in the common pool, move it. # If a config file exist in the common pool, move it.
if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ]; then
then
ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." ynh_print_info --message="Migrate to a dedicated php-fpm service for $app."
# Create a backup of the old file before migration # Create a backup of the old file before migration
ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf"
@ -150,13 +141,9 @@ ynh_add_fpm_config () {
fi fi
fi fi
if [ $use_template -eq 1 ] if [ $use_template -eq 1 ]; then
then
# Usage 1, use the template in conf/php-fpm.conf # Usage 1, use the template in conf/php-fpm.conf
local phpfpm_path="../conf/php-fpm.conf" local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
if [ ! -e "$phpfpm_path" ]; then
phpfpm_path="../settings/conf/php-fpm.conf" # Into the restore script, the PHP-FPM template is not at the same place
fi
# Make sure now that the template indeed exists # Make sure now that the template indeed exists
[ -e "$phpfpm_path" ] || ynh_die --message="Unable to find template to configure PHP-FPM." [ -e "$phpfpm_path" ] || ynh_die --message="Unable to find template to configure PHP-FPM."
else else
@ -169,7 +156,7 @@ ynh_add_fpm_config () {
# Define the values to use for the configuration of PHP. # Define the values to use for the configuration of PHP.
ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint
local phpfpm_path="../conf/php-fpm.conf" local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
echo " echo "
[__APP__] [__APP__]
@ -186,51 +173,47 @@ 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" ] if [ "$php_pm" = "dynamic" ]; then
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" ] elif [ "$php_pm" = "ondemand" ]; then
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.
if [ -e ../conf/extra_php-fpm.conf ]; then if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then
cat ../conf/extra_php-fpm.conf >> "$phpfpm_path" cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >>"$phpfpm_path"
fi fi
fi fi
local finalphpconf="$fpm_config_dir/pool.d/$app.conf" local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf" ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
if [ -e "../conf/php-fpm.ini" ] if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then
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="../conf/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 ] if [ $dedicated_service -eq 1 ]; then
then
# Create a dedicated php-fpm.conf for the service # Create a dedicated php-fpm.conf for the service
local globalphpconf=$fpm_config_dir/php-fpm-$app.conf local globalphpconf=$fpm_config_dir/php-fpm-$app.conf
echo "[global] echo "[global]
pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid
error_log = /var/log/php/fpm-php.__APP__.log error_log = /var/log/php/fpm-php.__APP__.log
syslog.ident = php-fpm-__APP__ syslog.ident = php-fpm-__APP__
include = __FINALPHPCONF__ include = __FINALPHPCONF__
" > ../conf/php-fpm-$app.conf " >$YNH_APP_BASEDIR/conf/php-fpm-$app.conf
ynh_add_config --template="../config/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]
@ -245,20 +228,19 @@ ExecReload=/bin/kill -USR2 \$MAINPID
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
" > ../conf/$fpm_service " >$YNH_APP_BASEDIR/conf/$fpm_service
# Create this dedicated PHP-FPM service # Create this dedicated PHP-FPM service
ynh_add_systemd_config --service=$fpm_service --template=$fpm_service ynh_add_systemd_config --service=$fpm_service --template=$fpm_service
# Integrate the service in YunoHost admin panel # Integrate the service in YunoHost admin panel
yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --log_type file --description "Php-fpm dedicated to $app" yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --description "Php-fpm dedicated to $app"
# Configure log rotate # Configure log rotate
ynh_use_logrotate --logfile=/var/log/php ynh_use_logrotate --logfile=/var/log/php
# Restart the service, as this service is either stopped or only for this app # Restart the service, as this service is either stopped or only for this app
ynh_systemd_action --service_name=$fpm_service --action=restart ynh_systemd_action --service_name=$fpm_service --action=restart
else else
# Validate that the new php conf doesn't break php-fpm entirely # Validate that the new php conf doesn't break php-fpm entirely
if ! php-fpm${phpversion} --test 2>/dev/null if ! php-fpm${phpversion} --test 2>/dev/null; then
then
php-fpm${phpversion} --test || true php-fpm${phpversion} --test || true
ynh_secure_remove --file="$finalphpconf" ynh_secure_remove --file="$finalphpconf"
ynh_die --message="The new configuration broke php-fpm?" ynh_die --message="The new configuration broke php-fpm?"
@ -272,7 +254,7 @@ WantedBy=multi-user.target
# usage: ynh_remove_fpm_config # usage: ynh_remove_fpm_config
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 2.7.2 or higher.
ynh_remove_fpm_config () { ynh_remove_fpm_config() {
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service) local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service)
@ -284,14 +266,17 @@ ynh_remove_fpm_config () {
phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}" phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}"
# Assume default PHP files if not set # Assume default PHP files if not set
if [ -z "$fpm_config_dir" ] if [ -z "$fpm_config_dir" ]; then
then
fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm" fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm"
fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm" fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm"
fi fi
if [ $dedicated_service -eq 1 ] ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
then if [ -e $fpm_config_dir/conf.d/20-$app.ini ]; then
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
fi
if [ $dedicated_service -eq 1 ]; then
# Remove the dedicated service PHP-FPM service for the app # Remove the dedicated service PHP-FPM service for the app
ynh_remove_systemd_config --service=$fpm_service ynh_remove_systemd_config --service=$fpm_service
# Remove the global PHP-FPM conf # Remove the global PHP-FPM conf
@ -302,15 +287,8 @@ ynh_remove_fpm_config () {
ynh_systemd_action --service_name=$fpm_service --action=reload ynh_systemd_action --service_name=$fpm_service --action=reload
fi fi
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]
then
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
fi
# If the PHP version used is not the default version for YunoHost # If the PHP version used is not the default version for YunoHost
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]; then
then
# Remove this specific version of PHP # Remove this specific version of PHP
ynh_remove_php ynh_remove_php
fi fi
@ -325,47 +303,22 @@ ynh_remove_fpm_config () {
# | arg: -p, --package= - Additionnal PHP packages to install # | arg: -p, --package= - Additionnal PHP packages to install
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_install_php () { ynh_install_php() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=vp local legacy_args=vp
local -A args_array=( [v]=phpversion= [p]=package= ) local -A args_array=([v]=phpversion= [p]=package=)
local phpversion local phpversion
local package local package
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
package=${package:-} package=${package:-}
# Store phpversion into the config of this app if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]; then
ynh_app_setting_set $app phpversion $phpversion ynh_die --message="Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]
then
ynh_die "Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
fi fi
# Create the file if doesn't exist already ynh_install_app_dependencies "$package"
touch /etc/php/ynh_app_version ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
# Do not add twice the same line
if ! grep --quiet "$YNH_APP_INSTANCE_NAME:" "/etc/php/ynh_app_version"
then
# Store the ID of this app and the version of PHP requested for it
echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version"
fi
# Add an extra repository for those packages
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
# Install requested dependencies from this extra repository.
# Install PHP-FPM first, otherwise PHP will install apache as a dependency.
ynh_add_app_dependencies --package="php${phpversion}-fpm"
ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package"
# Set the default PHP version back as the default version for php-cli.
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
# Advertise service in admin panel
yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log"
} }
# Remove the specific version of PHP used by the app. # Remove the specific version of PHP used by the app.
@ -376,35 +329,7 @@ ynh_install_php () {
# #
# Requires YunoHost version 3.8.1 or higher. # Requires YunoHost version 3.8.1 or higher.
ynh_remove_php () { ynh_remove_php () {
# Get the version of PHP used by this app ynh_remove_app_dependencies
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] || [ -z "$phpversion" ]
then
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]
then
ynh_print_err "Do not use ynh_remove_php to remove php$YNH_DEFAULT_PHP_VERSION !"
fi
return 0
fi
# Create the file if doesn't exist already
touch /etc/php/ynh_app_version
# Remove the line for this app
sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version"
# If no other app uses this version of PHP, remove it.
if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version"
then
# Remove the service from the admin panel
if ynh_package_is_installed --package="php${phpversion}-fpm"; then
yunohost service remove php${phpversion}-fpm
fi
# Purge PHP dependencies for this version.
ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common"
fi
} }
# Define the values to configure PHP-FPM # Define the values to configure PHP-FPM
@ -426,10 +351,10 @@ ynh_remove_php () {
# high - High usage, frequently visited website. # high - High usage, frequently visited website.
# #
# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app) # | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app)
ynh_get_scalable_phpfpm () { ynh_get_scalable_phpfpm() {
local legacy_args=ufp local legacy_args=ufp
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local -A args_array=( [u]=usage= [f]=footprint= [p]=print ) local -A args_array=([u]=usage= [f]=footprint= [p]=print)
local usage local usage
local footprint local footprint
local print local print
@ -440,38 +365,30 @@ ynh_get_scalable_phpfpm () {
usage=${usage,,} usage=${usage,,}
print=${print:-0} print=${print:-0}
if [ "$footprint" = "low" ] if [ "$footprint" = "low" ]; then
then
footprint=20 footprint=20
elif [ "$footprint" = "medium" ] elif [ "$footprint" = "medium" ]; then
then
footprint=35 footprint=35
elif [ "$footprint" = "high" ] elif [ "$footprint" = "high" ]; then
then
footprint=50 footprint=50
fi fi
# Define the factor to determine min_spare_servers # Define the factor to determine min_spare_servers
# to avoid having too few children ready to start for heavy apps # to avoid having too few children ready to start for heavy apps
if [ $footprint -le 20 ] if [ $footprint -le 20 ]; then
then
min_spare_servers_factor=8 min_spare_servers_factor=8
elif [ $footprint -le 35 ] elif [ $footprint -le 35 ]; then
then
min_spare_servers_factor=5 min_spare_servers_factor=5
else else
min_spare_servers_factor=3 min_spare_servers_factor=3
fi fi
# Define the way the process manager handle child processes. # Define the way the process manager handle child processes.
if [ "$usage" = "low" ] if [ "$usage" = "low" ]; then
then
php_pm=ondemand php_pm=ondemand
elif [ "$usage" = "medium" ] elif [ "$usage" = "medium" ]; then
then
php_pm=dynamic php_pm=dynamic
elif [ "$usage" = "high" ] elif [ "$usage" = "high" ]; then
then
php_pm=static php_pm=static
else else
ynh_die --message="Does not recognize '$usage' as an usage value." ynh_die --message="Does not recognize '$usage' as an usage value."
@ -482,8 +399,7 @@ ynh_get_scalable_phpfpm () {
at_least_one() { at_least_one() {
# Do not allow value below 1 # Do not allow value below 1
if [ $1 -le 0 ] if [ $1 -le 0 ]; then
then
echo 1 echo 1
else else
echo $1 echo $1
@ -493,20 +409,18 @@ ynh_get_scalable_phpfpm () {
# Define pm.max_children # Define pm.max_children
# The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app. # The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app.
# So if PHP-FPM start the maximum of children, it won't exceed half of the ram. # So if PHP-FPM start the maximum of children, it won't exceed half of the ram.
php_max_children=$(( $max_ram / 2 / $footprint )) php_max_children=$(($max_ram / 2 / $footprint))
# If process manager is set as static, use half less children. # If process manager is set as static, use half less children.
# Used as static, there's always as many children as the value of pm.max_children # Used as static, there's always as many children as the value of pm.max_children
if [ "$php_pm" = "static" ] if [ "$php_pm" = "static" ]; then
then php_max_children=$(($php_max_children / 2))
php_max_children=$(( $php_max_children / 2 ))
fi fi
php_max_children=$(at_least_one $php_max_children) php_max_children=$(at_least_one $php_max_children)
# To not overload the proc, limit the number of children to 4 times the number of cores. # To not overload the proc, limit the number of children to 4 times the number of cores.
local core_number=$(nproc) local core_number=$(nproc)
local max_proc=$(( $core_number * 4 )) local max_proc=$(($core_number * 4))
if [ $php_max_children -gt $max_proc ] if [ $php_max_children -gt $max_proc ]; then
then
php_max_children=$max_proc php_max_children=$max_proc
fi fi
@ -516,16 +430,15 @@ ynh_get_scalable_phpfpm () {
php_max_children=$php_forced_max_children php_max_children=$php_forced_max_children
fi fi
if [ "$php_pm" = "dynamic" ] if [ "$php_pm" = "dynamic" ]; then
then
# Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager
php_min_spare_servers=$(( $php_max_children / $min_spare_servers_factor )) php_min_spare_servers=$(($php_max_children / $min_spare_servers_factor))
php_min_spare_servers=$(at_least_one $php_min_spare_servers) php_min_spare_servers=$(at_least_one $php_min_spare_servers)
php_max_spare_servers=$(( $php_max_children / 2 )) php_max_spare_servers=$(($php_max_children / 2))
php_max_spare_servers=$(at_least_one $php_max_spare_servers) php_max_spare_servers=$(at_least_one $php_max_spare_servers)
php_start_servers=$(( $php_min_spare_servers + ( $php_max_spare_servers - $php_min_spare_servers ) /2 )) php_start_servers=$(($php_min_spare_servers + ($php_max_spare_servers - $php_min_spare_servers) / 2))
php_start_servers=$(at_least_one $php_start_servers) php_start_servers=$(at_least_one $php_start_servers)
else else
php_min_spare_servers=0 php_min_spare_servers=0
@ -533,27 +446,22 @@ ynh_get_scalable_phpfpm () {
php_start_servers=0 php_start_servers=0
fi fi
if [ $print -eq 1 ] if [ $print -eq 1 ]; then
then
ynh_debug --message="Footprint=${footprint}Mb by pool." ynh_debug --message="Footprint=${footprint}Mb by pool."
ynh_debug --message="Process manager=$php_pm" ynh_debug --message="Process manager=$php_pm"
ynh_debug --message="Max RAM=${max_ram}Mb" ynh_debug --message="Max RAM=${max_ram}Mb"
if [ "$php_pm" != "static" ] if [ "$php_pm" != "static" ]; then
then ynh_debug --message="\nMax estimated footprint=$(($php_max_children * $footprint))"
ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))" ynh_debug --message="Min estimated footprint=$(($php_min_spare_servers * $footprint))"
ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))"
fi fi
if [ "$php_pm" = "dynamic" ] if [ "$php_pm" = "dynamic" ]; then
then ynh_debug --message="Estimated average footprint=$(($php_max_spare_servers * $footprint))"
ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))" elif [ "$php_pm" = "static" ]; then
elif [ "$php_pm" = "static" ] ynh_debug --message="Estimated footprint=$(($php_max_children * $footprint))"
then
ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))"
fi fi
ynh_debug --message="\nRaw php-fpm values:" ynh_debug --message="\nRaw php-fpm values:"
ynh_debug --message="pm.max_children = $php_max_children" ynh_debug --message="pm.max_children = $php_max_children"
if [ "$php_pm" = "dynamic" ] if [ "$php_pm" = "dynamic" ]; then
then
ynh_debug --message="pm.start_servers = $php_start_servers" ynh_debug --message="pm.start_servers = $php_start_servers"
ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers" ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers"
ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers" ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers"
@ -572,10 +480,12 @@ YNH_COMPOSER_VERSION=${YNH_COMPOSER_VERSION:-$YNH_DEFAULT_COMPOSER_VERSION}
# | arg: -v, --phpversion - PHP version to use with composer # | 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: -w, --workdir - The directory from where the command will be executed. Default $final_path.
# | arg: -c, --commands - Commands to execute. # | arg: -c, --commands - Commands to execute.
ynh_composer_exec () { #
# Requires YunoHost version 4.2 or higher.
ynh_composer_exec() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=vwc local legacy_args=vwc
declare -Ar args_array=( [v]=phpversion= [w]=workdir= [c]=commands= ) declare -Ar args_array=([v]=phpversion= [w]=workdir= [c]=commands=)
local phpversion local phpversion
local workdir local workdir
local commands local commands
@ -584,7 +494,7 @@ ynh_composer_exec () {
workdir="${workdir:-$final_path}" workdir="${workdir:-$final_path}"
phpversion="${phpversion:-$YNH_PHP_VERSION}" phpversion="${phpversion:-$YNH_PHP_VERSION}"
COMPOSER_HOME="$workdir/.composer" \ COMPOSER_HOME="$workdir/.composer" COMPOSER_MEMORY_LIMIT=-1 \
php${phpversion} "$workdir/composer.phar" $commands \ php${phpversion} "$workdir/composer.phar" $commands \
-d "$workdir" --quiet --no-interaction -d "$workdir" --quiet --no-interaction
} }
@ -596,10 +506,12 @@ ynh_composer_exec () {
# | arg: -w, --workdir - The directory from where the command will be executed. Default $final_path. # | 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: -a, --install_args - Additional arguments provided to the composer install. Argument --no-dev already include
# | arg: -c, --composerversion - Composer version to install # | arg: -c, --composerversion - Composer version to install
ynh_install_composer () { #
# Requires YunoHost version 4.2 or higher.
ynh_install_composer() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=vwac local legacy_args=vwac
declare -Ar args_array=( [v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=) declare -Ar args_array=([v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
local phpversion local phpversion
local workdir local workdir
local install_args local install_args
@ -614,9 +526,9 @@ ynh_install_composer () {
curl -sS https://getcomposer.org/installer \ curl -sS https://getcomposer.org/installer \
| COMPOSER_HOME="$workdir/.composer" \ | COMPOSER_HOME="$workdir/.composer" \
php${phpversion} -- --quiet --install-dir="$workdir" --version=$composerversion \ php${phpversion} -- --quiet --install-dir="$workdir" --version=$composerversion \
|| ynh_die "Unable to install Composer." || ynh_die --message="Unable to install Composer."
# install dependencies # install dependencies
ynh_composer_exec --phpversion="${phpversion}" --workdir="$workdir" --commands="install --no-dev $install_args" \ ynh_composer_exec --phpversion="${phpversion}" --workdir="$workdir" --commands="install --no-dev $install_args" \
|| ynh_die "Unable to install core dependencies with Composer." || ynh_die --message="Unable to install core dependencies with Composer."
} }

View file

@ -5,15 +5,15 @@ PSQL_VERSION=11
# Open a connection as a user # Open a connection as a user
# #
# examples:
# ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"
# ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
#
# usage: ynh_psql_connect_as --user=user --password=password [--database=database] # usage: ynh_psql_connect_as --user=user --password=password [--database=database]
# | arg: -u, --user= - the user name to connect as # | arg: -u, --user= - the user name to connect as
# | arg: -p, --password= - the user password # | arg: -p, --password= - the user password
# | arg: -d, --database= - the database to connect to # | arg: -d, --database= - the database to connect to
# #
# examples:
# ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"
# ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
#
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_psql_connect_as() { ynh_psql_connect_as() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
@ -46,8 +46,7 @@ ynh_psql_execute_as_root() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
database="${database:-}" database="${database:-}"
if [ -n "$database" ] if [ -n "$database" ]; then
then
database="--database=$database" database="--database=$database"
fi fi
@ -72,8 +71,7 @@ ynh_psql_execute_file_as_root() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
database="${database:-}" database="${database:-}"
if [ -n "$database" ] if [ -n "$database" ]; then
then
database="--database=$database" database="--database=$database"
fi fi
@ -127,12 +125,12 @@ ynh_psql_drop_db() {
# Dump a database # Dump a database
# #
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
#
# usage: ynh_psql_dump_db --database=database # usage: ynh_psql_dump_db --database=database
# | arg: -d, --database= - the database name to dump # | arg: -d, --database= - the database name to dump
# | ret: the psqldump output # | ret: the psqldump output
# #
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
#
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_psql_dump_db() { ynh_psql_dump_db() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
@ -175,8 +173,7 @@ ynh_psql_user_exists() {
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user"; then
then
return 1 return 1
else else
return 0 return 0
@ -198,8 +195,7 @@ ynh_psql_database_exists() {
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
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" 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
then
return 1 return 1
else else
return 0 return 0
@ -269,16 +265,14 @@ ynh_psql_remove_db() {
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
if ynh_psql_database_exists --database=$db_name if ynh_psql_database_exists --database=$db_name; then # Check if the database exists
then # Check if the database exists
ynh_psql_drop_db $db_name # Remove the database ynh_psql_drop_db $db_name # Remove the database
else else
ynh_print_warn --message="Database $db_name not found" ynh_print_warn --message="Database $db_name not found"
fi fi
# Remove psql user if it exists # Remove psql user if it exists
if ynh_psql_user_exists --user=$db_user if ynh_psql_user_exists --user=$db_user; then
then
ynh_psql_drop_user $db_user ynh_psql_drop_user $db_user
else else
ynh_print_warn --message="User $db_user not found" ynh_print_warn --message="User $db_user not found"
@ -286,19 +280,20 @@ ynh_psql_remove_db() {
} }
# Create a master password and set up global settings # Create a master password and set up global settings
# It also make sure that postgresql is installed and running
# Please always call this script in install and restore scripts
# #
# usage: ynh_psql_test_if_first_run # usage: ynh_psql_test_if_first_run
# #
# It also make sure that postgresql is installed and running
# Please always call this script in install and restore scripts
#
# Requires YunoHost version 2.7.13 or higher. # Requires YunoHost version 2.7.13 or higher.
ynh_psql_test_if_first_run() { 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 "postgresql-$PSQL_VERSION is not installed !?" dpkg --list | grep -q "ii postgresql-$PSQL_VERSION" || ynh_die --message="postgresql-$PSQL_VERSION is not installed !?"
# Check for some weird issue where postgresql could be installed but etc folder would not exist ... # Check for some weird issue where postgresql could be installed but etc folder would not exist ...
[ -e "/etc/postgresql/$PSQL_VERSION" ] || ynh_die "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" [ -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 # Make sure postgresql is started and enabled
# (N.B. : to check the active state, we check the cluster state because # (N.B. : to check the active state, we check the cluster state because
@ -309,8 +304,7 @@ ynh_psql_test_if_first_run() {
# If this is the very first time, we define the root password # If this is the very first time, we define the root password
# and configure a few things # and configure a few things
if [ ! -f "$PSQL_ROOT_PWD_FILE" ] if [ ! -f "$PSQL_ROOT_PWD_FILE" ]; then
then
local pg_hba=/etc/postgresql/$PSQL_VERSION/main/pg_hba.conf local pg_hba=/etc/postgresql/$PSQL_VERSION/main/pg_hba.conf
local psql_root_password="$(ynh_string_random)" local psql_root_password="$(ynh_string_random)"

View file

@ -10,7 +10,7 @@
ynh_app_setting_get() { ynh_app_setting_get() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=ak local legacy_args=ak
local -A args_array=( [a]=app= [k]=key= ) local -A args_array=([a]=app= [k]=key=)
local app local app
local key local key
# Manage arguments with getopts # Manage arguments with getopts
@ -34,7 +34,7 @@ ynh_app_setting_get() {
ynh_app_setting_set() { ynh_app_setting_set() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=akv local legacy_args=akv
local -A args_array=( [a]=app= [k]=key= [v]=value= ) local -A args_array=([a]=app= [k]=key= [v]=value=)
local app local app
local key local key
local value local value
@ -58,7 +58,7 @@ ynh_app_setting_set() {
ynh_app_setting_delete() { ynh_app_setting_delete() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=ak local legacy_args=ak
local -A args_array=( [a]=app= [k]=key= ) local -A args_array=([a]=app= [k]=key=)
local app local app
local key local key
# Manage arguments with getopts # Manage arguments with getopts
@ -76,8 +76,7 @@ ynh_app_setting_delete() {
# #
# [internal] # [internal]
# #
ynh_app_setting() ynh_app_setting() {
{
set +o xtrace # set +x set +o xtrace # set +x
ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python3 - <<EOF ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python3 - <<EOF
import os, yaml, sys import os, yaml, sys
@ -86,7 +85,7 @@ key, value = os.environ['KEY'], os.environ.get('VALUE', None)
setting_file = "/etc/yunohost/apps/%s/settings.yml" % app setting_file = "/etc/yunohost/apps/%s/settings.yml" % app
assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file
with open(setting_file) as f: with open(setting_file) as f:
settings = yaml.load(f) settings = yaml.safe_load(f)
if action == "get": if action == "get":
if key in settings: if key in settings:
print(settings[key]) print(settings[key])
@ -96,7 +95,7 @@ else:
del settings[key] del settings[key]
elif action == "set": elif action == "set":
if key in ['redirected_urls', 'redirected_regex']: if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value) value = yaml.safe_load(value)
settings[key] = value settings[key] = value
else: else:
raise ValueError("action should either be get, set or delete") raise ValueError("action should either be get, set or delete")
@ -108,17 +107,17 @@ EOF
# Check availability of a web path # Check availability of a web path
# #
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
#
# 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
# #
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
#
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_webpath_available () { ynh_webpath_available() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=dp local legacy_args=dp
local -A args_array=( [d]=domain= [p]=path_url= ) local -A args_array=([d]=domain= [p]=path_url=)
local domain local domain
local path_url local path_url
# Manage arguments with getopts # Manage arguments with getopts
@ -129,18 +128,18 @@ ynh_webpath_available () {
# Register/book a web path for an app # Register/book a web path for an app
# #
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
#
# 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
# | arg: -p, --path_url= - the web path to be registered # | arg: -p, --path_url= - the web path to be registered
# #
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
#
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_webpath_register () { ynh_webpath_register() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=adp local legacy_args=adp
local -A args_array=( [a]=app= [d]=domain= [p]=path_url= ) local -A args_array=([a]=app= [d]=domain= [p]=path_url=)
local app local app
local domain local domain
local path_url local path_url

View file

@ -2,23 +2,23 @@
# Generate a random string # Generate a random string
# #
# example: pwd=$(ynh_string_random --length=8)
#
# 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)
# | ret: the generated string # | ret: the generated string
# #
# example: pwd=$(ynh_string_random --length=8)
#
# 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=l local legacy_args=l
local -A args_array=( [l]=length= ) local -A args_array=([l]=length=)
local length local length
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
length=${length:-24} length=${length:-24}
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 'A-Za-z0-9' \ | tr --complement --delete 'A-Za-z0-9' \
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p' | sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
} }
@ -30,26 +30,27 @@ ynh_string_random() {
# | arg: -r, --replace_string= - String that will replace matches # | arg: -r, --replace_string= - String that will replace matches
# | arg: -f, --target_file= - File in which the string will be replaced. # | arg: -f, --target_file= - File in which the string will be replaced.
# #
# As this helper is based on sed command, regular expressions and # As this helper is based on sed command, regular expressions and references to
# references to sub-expressions can be used # sub-expressions can be used (see sed manual page for more information)
# (see sed manual page for more information)
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_replace_string () { ynh_replace_string() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mrf local legacy_args=mrf
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) local -A args_array=([m]=match_string= [r]=replace_string= [f]=target_file=)
local match_string local match_string
local replace_string local replace_string
local target_file local target_file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
set +o xtrace # set +x
local delimit=@ 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}"}
set -o xtrace # set -x
sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file"
} }
@ -64,10 +65,10 @@ ynh_replace_string () {
# characters, you can't use some regular expressions and sub-expressions. # characters, you can't use some regular expressions and sub-expressions.
# #
# Requires YunoHost version 2.7.7 or higher. # Requires YunoHost version 2.7.7 or higher.
ynh_replace_special_string () { ynh_replace_special_string() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mrf local legacy_args=mrf
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) local -A args_array=([m]=match_string= [r]=replace_string= [f]=target_file=)
local match_string local match_string
local replace_string local replace_string
local target_file local target_file
@ -86,19 +87,20 @@ 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
# (More specifically : replace - and . by _)
#
# example: dbname=$(ynh_sanitize_dbid $app)
# #
# 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
# #
# example: dbname=$(ynh_sanitize_dbid $app)
#
# Underscorify the string (replace - and . by _)
#
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_sanitize_dbid () { ynh_sanitize_dbid() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=n local legacy_args=n
local -A args_array=( [n]=db_name= ) local -A args_array=([n]=db_name=)
local db_name local db_name
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -125,10 +127,10 @@ ynh_sanitize_dbid () {
# | arg: -p, --path_url= - URL path to normalize before using it # | arg: -p, --path_url= - URL path to normalize before using it
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_normalize_url_path () { ynh_normalize_url_path() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=p local legacy_args=p
local -A args_array=( [p]=path_url= ) local -A args_array=([p]=path_url=)
local path_url local path_url
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"

View file

@ -3,26 +3,31 @@
# Create a dedicated systemd config # Create a dedicated systemd config
# #
# usage: ynh_add_systemd_config [--service=service] [--template=template] # usage: ynh_add_systemd_config [--service=service] [--template=template]
# | arg: -s, --service= - Service name (optionnal, $app by default) # | arg: -s, --service= - Service name (optionnal, `$app` by default)
# | arg: -t, --template= - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) # | arg: -t, --template= - Name of template file (optionnal, this is 'systemd' by default, meaning `../conf/systemd.service` will be used as template)
# #
# This will use the template ../conf/<templatename>.service # This will use the template `../conf/<templatename>.service`.
# 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
# format and how placeholders are replaced with actual variables. # format and how placeholders are replaced with actual variables.
# #
# Requires YunoHost version 2.7.11 or higher. # Requires YunoHost version 4.1.0 or higher.
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=st 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 "$@"
local service="${service:-$app}" service="${service:-$app}"
local template="${template:-systemd.service}" template="${template:-systemd.service}"
others_var="${others_var:-}"
ynh_add_config --template="../conf/$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
@ -34,18 +39,17 @@ ynh_add_systemd_config () {
# | arg: -s, --service= - Service name (optionnal, $app by default) # | arg: -s, --service= - Service name (optionnal, $app by default)
# #
# Requires YunoHost version 2.7.2 or higher. # Requires YunoHost version 2.7.2 or higher.
ynh_remove_systemd_config () { ynh_remove_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=s local legacy_args=s
local -A args_array=( [s]=service= ) local -A args_array=([s]=service=)
local service local service
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local service="${service:-$app}" local service="${service:-$app}"
local finalsystemdconf="/etc/systemd/system/$service.service" local finalsystemdconf="/etc/systemd/system/$service.service"
if [ -e "$finalsystemdconf" ] if [ -e "$finalsystemdconf" ]; then
then
ynh_systemd_action --service_name=$service --action=stop ynh_systemd_action --service_name=$service --action=stop
systemctl disable $service --quiet systemctl disable $service --quiet
ynh_secure_remove --file="$finalsystemdconf" ynh_secure_remove --file="$finalsystemdconf"
@ -56,10 +60,10 @@ ynh_remove_systemd_config () {
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started # Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
# #
# usage: ynh_systemd_action [--service_name=service_name] [--action=action] [ [--line_match="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ] # usage: ynh_systemd_action [--service_name=service_name] [--action=action] [ [--line_match="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ]
# | arg: -n, --service_name= - Name of the service to start. Default : $app # | arg: -n, --service_name= - Name of the service to start. Default : `$app`
# | arg: -a, --action= - Action to perform with systemctl. Default: start # | arg: -a, --action= - Action to perform with systemctl. Default: start
# | 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. WARNING: When using --line_match, you should always add `ynh_clean_check_starting` into your `ynh_clean_setup` at the beginning of the script. Otherwise, tail will not stop in case of failure of the script. The script will then hang forever. # | 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 : Default : 20 # | arg: -e, --length= - Length of the error log : Default : 20
# #
@ -67,7 +71,7 @@ ynh_remove_systemd_config () {
ynh_systemd_action() { ynh_systemd_action() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=nalpte local legacy_args=nalpte
local -A args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= ) local -A args_array=([n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length=)
local service_name local service_name
local action local action
local line_match local line_match
@ -83,20 +87,23 @@ ynh_systemd_action() {
log_path="${log_path:-/var/log/$service_name/$service_name.log}" log_path="${log_path:-/var/log/$service_name/$service_name.log}"
timeout=${timeout:-300} timeout=${timeout:-300}
# Manage case of service already stopped
if [ "$action" == "stop" ] && ! systemctl is-active --quiet $service_name; then
return 0
fi
# Start to read the log # Start to read the log
if [[ -n "$line_match" ]] if [[ -n "$line_match" ]]; then
then
local templog="$(mktemp)" local templog="$(mktemp)"
# Following the starting of the app in its log # Following the starting of the app in its log
if [ "$log_path" == "systemd" ] if [ "$log_path" == "systemd" ]; then
then
# Read the systemd journal # Read the systemd journal
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" & journalctl --unit=$service_name --follow --since=-0 --quiet >"$templog" &
# Get the PID of the journalctl command # Get the PID of the journalctl command
local pid_tail=$! local pid_tail=$!
else else
# Read the specified log file # Read the specified log file
tail --follow=name --retry --lines=0 "$log_path" > "$templog" 2>&1 & tail --follow=name --retry --lines=0 "$log_path" >"$templog" 2>&1 &
# Get the PID of the tail command # Get the PID of the tail command
local pid_tail=$! local pid_tail=$!
fi fi
@ -108,36 +115,29 @@ ynh_systemd_action() {
fi fi
# If the service fails to perform the action # If the service fails to perform the action
if ! systemctl $action $service_name if ! systemctl $action $service_name; then
then
# Show syslog for this service # Show syslog for this service
ynh_exec_err journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name ynh_exec_err journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
# If a log is specified for this service, show also the content of this log # If a log is specified for this service, show also the content of this log
if [ -e "$log_path" ] if [ -e "$log_path" ]; then
then
ynh_exec_err tail --lines=$length "$log_path" ynh_exec_err tail --lines=$length "$log_path"
fi fi
ynh_clean_check_starting
return 1 return 1
fi fi
# Start the timeout and try to find line_match # Start the timeout and try to find line_match
if [[ -n "${line_match:-}" ]] if [[ -n "${line_match:-}" ]]; then
then
set +x set +x
local i=0 local i=0
for i in $(seq 1 $timeout) for i in $(seq 1 $timeout); do
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 grep --extended-regexp --quiet "$line_match" "$templog" if grep --extended-regexp --quiet "$line_match" "$templog"; then
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
if [ $i -eq 3 ]; then if [ $i -eq 30 ]; then
echo -n "Please wait, the service $service_name is ${action}ing" >&2 echo "(this may take some time)" >&2
fi
if [ $i -ge 3 ]; then
echo -n "." >&2
fi fi
sleep 1 sleep 1
done done
@ -145,13 +145,11 @@ ynh_systemd_action() {
if [ $i -ge 3 ]; then if [ $i -ge 3 ]; then
echo "" >&2 echo "" >&2
fi fi
if [ $i -eq $timeout ] if [ $i -eq $timeout ]; then
then
ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout." ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout."
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:" ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
ynh_exec_warn journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name ynh_exec_warn journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
if [ -e "$log_path" ] if [ -e "$log_path" ]; then
then
ynh_print_warn --message="\-\-\-" ynh_print_warn --message="\-\-\-"
ynh_exec_warn tail --lines=$length "$log_path" ynh_exec_warn tail --lines=$length "$log_path"
fi fi
@ -161,20 +159,16 @@ ynh_systemd_action() {
} }
# Clean temporary process and file used by ynh_check_starting # Clean temporary process and file used by ynh_check_starting
# (usually used in ynh_clean_setup scripts)
# #
# usage: ynh_clean_check_starting # [internal]
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_clean_check_starting () { ynh_clean_check_starting() {
if [ -n "$pid_tail" ] if [ -n "${pid_tail:-}" ]; then
then
# Stop the execution of tail. # Stop the execution of tail.
kill -SIGTERM $pid_tail 2>&1 kill -SIGTERM $pid_tail 2>&1
fi fi
if [ -n "$templog" ] if [ -n "${templog:-}" ]; then
then ynh_secure_remove --file="$templog" 2>&1
ynh_secure_remove "$templog" 2>&1
fi fi
} }

View file

@ -2,70 +2,69 @@
# Check if a YunoHost user exists # Check if a YunoHost user exists
# #
# example: ynh_user_exists 'toto' || exit 1
#
# usage: ynh_user_exists --username=username # usage: ynh_user_exists --username=username
# | arg: -u, --username= - the username to check # | arg: -u, --username= - the username to check
# | exit: Return 1 if the user doesn't exist, 0 otherwise # | 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. # Requires YunoHost version 2.2.4 or higher.
ynh_user_exists() { ynh_user_exists() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=u local legacy_args=u
local -A args_array=( [u]=username= ) local -A args_array=([u]=username=)
local username local username
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
yunohost user list --output-as json | grep --quiet "\"username\": \"${username}\"" yunohost user list --output-as json --quiet | jq -e ".users.${username}" >/dev/null
} }
# Retrieve a YunoHost user information # Retrieve a YunoHost user information
# #
# example: mail=$(ynh_user_get_info 'toto' 'mail')
#
# usage: ynh_user_get_info --username=username --key=key # usage: ynh_user_get_info --username=username --key=key
# | arg: -u, --username= - the username to retrieve info from # | arg: -u, --username= - the username to retrieve info from
# | arg: -k, --key= - the key to retrieve # | arg: -k, --key= - the key to retrieve
# | ret: string - the key's value # | ret: the value associate to that key
#
# example: mail=$(ynh_user_get_info 'toto' 'mail')
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_user_get_info() { ynh_user_get_info() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=uk local legacy_args=uk
local -A args_array=( [u]=username= [k]=key= ) local -A args_array=([u]=username= [k]=key=)
local username local username
local key local key
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
yunohost user info "$username" --output-as plain | ynh_get_plain_key "$key" yunohost user info "$username" --output-as json --quiet | jq -r ".$key"
} }
# Get the list of YunoHost users # Get the list of YunoHost users
# #
# example: for u in $(ynh_user_list); do ...
#
# usage: ynh_user_list # usage: ynh_user_list
# | ret: string - one username per line # | ret: one username per line as strings
#
# example: for u in $(ynh_user_list); do ... ; done
# #
# Requires YunoHost version 2.4.0 or higher. # Requires YunoHost version 2.4.0 or higher.
ynh_user_list() { ynh_user_list() {
yunohost user list --output-as plain --quiet \ yunohost user list --output-as json --quiet | jq -r ".users | keys[]"
| awk '/^##username$/{getline; print}'
} }
# Check if a user exists on the system # 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
# | exit: Return 1 if the user doesn't exist, 0 otherwise # | ret: 0 if the user exists, 1 otherwise.
# #
# Requires YunoHost version 2.2.4 or higher. # Requires YunoHost version 2.2.4 or higher.
ynh_system_user_exists() { ynh_system_user_exists() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=u local legacy_args=u
local -A args_array=( [u]=username= ) local -A args_array=([u]=username=)
local username local username
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -77,13 +76,13 @@ ynh_system_user_exists() {
# #
# 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
# | exit: Return 1 if the group doesn't exist, 0 otherwise # | ret: 0 if the group exists, 1 otherwise.
# #
# Requires YunoHost version 3.5.0.2 or higher. # Requires YunoHost version 3.5.0.2 or higher.
ynh_system_group_exists() { ynh_system_group_exists() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=g local legacy_args=g
local -A args_array=( [g]=group= ) local -A args_array=([g]=group=)
local group local group
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -93,46 +92,56 @@ ynh_system_group_exists() {
# Create a system user # Create a system user
# #
# examples: # usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell] [--groups="group1 group2"]
# # Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability)
# ynh_system_user_create --username=nextcloud
# # Create a discourse user using /var/www/discourse as home directory and the default login shell
# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell
#
# usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell]
# | arg: -u, --username= - Name of the system user that will be create # | arg: -u, --username= - Name of the system user that will be create
# | arg: -h, --home_dir= - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home # | arg: -h, --home_dir= - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell # | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell
# | arg: -g, --groups - Add the user to system groups. Typically meant to add the user to the ssh.app / sftp.app group (e.g. for borgserver, my_webapp)
#
# Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability) :
# ```
# ynh_system_user_create --username=nextcloud
# ```
# Create a discourse user using /var/www/discourse as home directory and the default login shell :
# ```
# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell
# ```
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_system_user_create () { ynh_system_user_create() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=uhs local legacy_args=uhs
local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell ) local -A args_array=([u]=username= [h]=home_dir= [s]=use_shell [g]=groups=)
local username local username
local home_dir local home_dir
local use_shell local use_shell
local groups
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
use_shell="${use_shell:-0}" use_shell="${use_shell:-0}"
home_dir="${home_dir:-}" home_dir="${home_dir:-}"
groups="${groups:-}"
if ! ynh_system_user_exists "$username" # Check if the user exists on the system if ! ynh_system_user_exists "$username"; then # Check if the user exists on the system
then # If the user doesn't exist # If the user doesn't exist
if [ -n "$home_dir" ] if [ -n "$home_dir" ]; then # If a home dir is mentioned
then # If a home dir is mentioned
local user_home_dir="--home-dir $home_dir" local user_home_dir="--home-dir $home_dir"
else else
local user_home_dir="--no-create-home" local user_home_dir="--no-create-home"
fi fi
if [ $use_shell -eq 1 ] if [ $use_shell -eq 1 ]; then # If we want a shell for the user
then # If we want a shell for the user
local shell="" # Use default shell local shell="" # Use default shell
else else
local shell="--shell /usr/sbin/nologin" local shell="--shell /usr/sbin/nologin"
fi fi
useradd $user_home_dir --system --user-group $username $shell || ynh_die --message="Unable to create $username system account" useradd $user_home_dir --system --user-group $username $shell || ynh_die --message="Unable to create $username system account"
fi fi
local group
for group in $groups; do
usermod -a -G "$group" "$username"
done
} }
# Delete a system user # Delete a system user
@ -141,25 +150,23 @@ ynh_system_user_create () {
# | arg: -u, --username= - Name of the system user that will be create # | arg: -u, --username= - Name of the system user that will be create
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_system_user_delete () { ynh_system_user_delete() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=u local legacy_args=u
local -A args_array=( [u]=username= ) local -A args_array=([u]=username=)
local username local username
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# Check if the user exists on the system # Check if the user exists on the system
if ynh_system_user_exists "$username" if ynh_system_user_exists "$username"; then
then
deluser $username deluser $username
else else
ynh_print_warn --message="The user $username was not found" ynh_print_warn --message="The user $username was not found"
fi fi
# Check if the group exists on the system # Check if the group exists on the system
if ynh_system_group_exists "$username" if ynh_system_group_exists "$username"; then
then
delgroup $username delgroup $username
fi fi
} }

View file

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
# Handle script crashes / failures # Handle script crashes / failures
# #
# [internal] # [internal]
@ -17,8 +19,11 @@
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app 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. # Requires YunoHost version 2.6.4 or higher.
ynh_exit_properly () { ynh_exit_properly() {
local exit_code=$? local exit_code=$?
rm -rf "/var/cache/yunohost/download/"
if [ "$exit_code" -eq 0 ]; then if [ "$exit_code" -eq 0 ]; then
exit 0 # Exit without error if the script ended correctly exit 0 # Exit without error if the script ended correctly
fi fi
@ -31,7 +36,7 @@ ynh_exit_properly () {
# Small tempo to avoid the next message being mixed up with other DEBUG messages # Small tempo to avoid the next message being mixed up with other DEBUG messages
sleep 0.5 sleep 0.5
if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script. 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. ynh_clean_setup # Call the function to do specific cleaning for the app.
fi fi
@ -46,12 +51,11 @@ ynh_exit_properly () {
# usage: ynh_abort_if_errors # usage: ynh_abort_if_errors
# #
# This configure the rest of the script execution such that, if an error occurs # 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 # or if an empty variable is used, the execution of the script stops immediately
# immediately and a call to `ynh_clean_setup` is triggered if it has been # and a call to `ynh_clean_setup` is triggered if it has been defined by your script.
# defined by your script.
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_abort_if_errors () { ynh_abort_if_errors() {
set -o errexit # set -e; Exit if a command fail set -o errexit # set -e; Exit if a command fail
set -o nounset # set -u; And if a variable is used unset set -o nounset # set -u; And if a variable is used unset
trap ynh_exit_properly EXIT # Capturing exit signals on shell script trap ynh_exit_properly EXIT # Capturing exit signals on shell script
@ -59,65 +63,55 @@ ynh_abort_if_errors () {
# Download, check integrity, uncompress and patch the source from app.src # Download, check integrity, uncompress and patch the source from app.src
# #
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] # 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: -d, --dest_dir= - Directory where to setup sources
# | arg: -s, --source_id= - Name of the app, if the package contains more than one app # | 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/'
# #
# The file conf/app.src need to contains: # 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_URL=Address to download the app archive
# SOURCE_SUM=Control sum # SOURCE_SUM=Control sum
# # (Optional) Program to check the integrity (sha256sum, md5sum...) # # (Optional) Program to check the integrity (sha256sum, md5sum...). Default: sha256
# # default: sha256
# SOURCE_SUM_PRG=sha256 # SOURCE_SUM_PRG=sha256
# # (Optional) Archive format # # (Optional) Archive format. Default: tar.gz
# # default: tar.gz
# SOURCE_FORMAT=tar.gz # SOURCE_FORMAT=tar.gz
# # (Optional) Put false if sources are directly in the archive root # # (Optional) Put false if sources are directly in the archive root. Default: true
# # default: true # # Instead of true, SOURCE_IN_SUBDIR could be the number of sub directories to remove.
# # Instead of true, SOURCE_IN_SUBDIR could be the number of sub directories
# # to remove.
# SOURCE_IN_SUBDIR=false # SOURCE_IN_SUBDIR=false
# # (Optionnal) Name of the local archive (offline setup support) # # (Optionnal) Name of the local archive (offline setup support). Default: ${src_id}.${src_format}
# # default: ${src_id}.${src_format}
# SOURCE_FILENAME=example.tar.gz # SOURCE_FILENAME=example.tar.gz
# # (Optional) If it set as false don't extract the source. # # (Optional) If it set as false don't extract the source. Default: true
# # (Useful to get a debian package or a python wheel.) # # (Useful to get a debian package or a python wheel.)
# # default: true
# SOURCE_EXTRACT=(true|false) # SOURCE_EXTRACT=(true|false)
# ```
# #
# Details: # The helper will:
# This helper downloads sources from SOURCE_URL if there is no local source # - Check if there is a local source archive in `/opt/yunohost-apps-src/$APP_ID/$SOURCE_FILENAME`
# 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`
# Next, it checks the integrity with "SOURCE_SUM_PRG -c --status" command. # - Uncompress the archive to `$dest_dir`.
# # - If `$SOURCE_IN_SUBDIR` is true, the first level directory of the archive will be removed.
# If it's ok, the source archive will be uncompressed in $dest_dir. If the # - If `$SOURCE_IN_SUBDIR` is a numeric value, the N first level directories will be removed.
# SOURCE_IN_SUBDIR is true, the first level directory of the archive will be # - Patches named `sources/patches/${src_id}-*.patch` will be applied to `$dest_dir`
# removed. # - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir
# If SOURCE_IN_SUBDIR is a numeric value, 2 for example, the 2 first level
# directories will be removed
#
# Finally, patches named sources/patches/${src_id}-*.patch and extra files in
# sources/extra_files/$src_id will be applied to dest_dir
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_setup_source () { ynh_setup_source() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=ds local legacy_args=dsk
local -A args_array=( [d]=dest_dir= [s]=source_id= ) local -A args_array=([d]=dest_dir= [s]=source_id= [k]=keep=)
local dest_dir local dest_dir
local source_id local source_id
local keep
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
source_id="${source_id:-app}" # If the argument is not given, source_id equals "app" source_id="${source_id:-app}"
keep="${keep:-}"
local src_file_path="$YNH_CWD/../conf/${source_id}.src" local src_file_path="$YNH_APP_BASEDIR/conf/${source_id}.src"
# In case of restore script the src file is in an other path.
# So try to use the restore path if the general path point to no file.
if [ ! -e "$src_file_path" ]; then
src_file_path="$YNH_CWD/../settings/conf/${source_id}.src"
fi
# Load value from configuration file (see above for a small doc about this file # Load value from configuration file (see above for a small doc about this file
# format) # format)
@ -138,12 +132,18 @@ ynh_setup_source () {
if [ "$src_filename" = "" ]; then if [ "$src_filename" = "" ]; then
src_filename="${source_id}.${src_format}" src_filename="${source_id}.${src_format}"
fi 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}" local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}"
if test -e "$local_src" mkdir -p /var/cache/yunohost/download/${YNH_APP_ID}/
then # Use the local source file if it is present src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${src_filename}"
if test -e "$local_src"; then
cp $local_src $src_filename cp $local_src $src_filename
else # If not, download the source 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, # NB. we have to declare the var as local first,
# otherwise 'local foo=$(false) || echo 'pwet'" does'nt work # otherwise 'local foo=$(false) || echo 'pwet'" does'nt work
# because local always return 0 ... # because local always return 0 ...
@ -157,18 +157,34 @@ ynh_setup_source () {
echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \ echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \
|| ynh_die --message="Corrupt source" || 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 # Extract source into the app dir
mkdir --parents "$dest_dir" mkdir --parents "$dest_dir"
if ! "$src_extract" if [ -n "${final_path:-}" ] && [ "$dest_dir" == "$final_path" ]; then
then _ynh_apply_default_permissions $dest_dir
fi
if ! "$src_extract"; then
mv $src_filename $dest_dir mv $src_filename $dest_dir
elif [ "$src_format" = "zip" ] elif [ "$src_format" = "zip" ]; then
then
# Zip format # Zip format
# Using of a temp directory, because unzip doesn't manage --strip-components # Using of a temp directory, because unzip doesn't manage --strip-components
if $src_in_subdir if $src_in_subdir; then
then
local tmp_dir=$(mktemp --directory) local tmp_dir=$(mktemp --directory)
unzip -quo $src_filename -d "$tmp_dir" unzip -quo $src_filename -d "$tmp_dir"
cp --archive $tmp_dir/*/. "$dest_dir" cp --archive $tmp_dir/*/. "$dest_dir"
@ -176,58 +192,75 @@ ynh_setup_source () {
else else
unzip -quo $src_filename -d "$dest_dir" unzip -quo $src_filename -d "$dest_dir"
fi fi
ynh_secure_remove --file="$src_filename"
else else
local strip="" local strip=""
if [ "$src_in_subdir" != "false" ] if [ "$src_in_subdir" != "false" ]; then
then if [ "$src_in_subdir" == "true" ]; then
if [ "$src_in_subdir" == "true" ]
then
local sub_dirs=1 local sub_dirs=1
else else
local sub_dirs="$src_in_subdir" local sub_dirs="$src_in_subdir"
fi fi
strip="--strip-components $sub_dirs" strip="--strip-components $sub_dirs"
fi fi
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]]; then
then
tar --extract --file=$src_filename --directory="$dest_dir" $strip tar --extract --file=$src_filename --directory="$dest_dir" $strip
else else
ynh_die --message="Archive format unrecognized." ynh_die --message="Archive format unrecognized."
fi fi
ynh_secure_remove --file="$src_filename"
fi fi
# Apply patches # Apply patches
if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc --lines) > "0" )) if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]; then
then local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/)
(cd "$dest_dir" if (($(find $patches_folder -type f -name "${source_id}-*.patch" 2>/dev/null | wc --lines) > "0")); then
for p in $YNH_CWD/../sources/patches/${source_id}-*.patch (
do cd "$dest_dir"
patch --strip=1 < $p for p in $patches_folder/${source_id}-*.patch; do
done) || ynh_die --message="Unable to apply patches" echo $p
patch --strip=1 <$p
done
) || ynh_die --message="Unable to apply patches"
fi
fi fi
# Add supplementary files # Add supplementary files
if test -e "$YNH_CWD/../sources/extra_files/${source_id}"; then if test -e "$YNH_APP_BASEDIR/sources/extra_files/${source_id}"; then
cp --archive $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir" cp --archive $YNH_APP_BASEDIR/sources/extra_files/$source_id/. "$dest_dir"
fi 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) # Curl abstraction to help with POST requests to local pages (such as installation forms)
# #
# example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"
#
# usage: ynh_local_curl "page_uri" "key1=value1" "key2=value2" ... # 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: 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: key1=value1 - (Optionnal) POST key and corresponding value
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value # | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
# | arg: ... - (Optionnal) More POST keys and values # | 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 # 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?)) # `$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. # Requires YunoHost version 2.6.4 or higher.
ynh_local_curl () { ynh_local_curl() {
# Define url of page to curl # Define url of page to curl
local local_page=$(ynh_normalize_url_path $1) local local_page=$(ynh_normalize_url_path $1)
local full_path=$path_url$local_page local full_path=$path_url$local_page
@ -241,12 +274,10 @@ ynh_local_curl () {
# Concatenate all other arguments with '&' to prepare POST data # Concatenate all other arguments with '&' to prepare POST data
local POST_data="" local POST_data=""
local arg="" local arg=""
for arg in "${@:2}" for arg in "${@:2}"; do
do
POST_data="${POST_data}${arg}&" POST_data="${POST_data}${arg}&"
done done
if [ -n "$POST_data" ] if [ -n "$POST_data" ]; then
then
# Add --data arg and remove the last character, which is an unecessary '&' # Add --data arg and remove the last character, which is an unecessary '&'
POST_data="--data ${POST_data::-1}" POST_data="--data ${POST_data::-1}"
fi fi
@ -265,20 +296,22 @@ ynh_local_curl () {
# Create a dedicated config file from a template # 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: # examples:
# ynh_add_config --template=".env" --destination="$final_path/.env" # ynh_add_config --template=".env" --destination="$final_path/.env"
# ynh_add_config --template="../conf/.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" # ynh_add_config --template="/etc/nginx/sites-available/default" --destination="etc/nginx/sites-available/mydomain.conf"
# #
# usage: ynh_add_config --template="template" --destination="destination"
# | arg: -t, --template= - Template config file to use
# | arg: -d, --destination= - Destination of the config file
#
# The template can be by default the name of a file in the conf directory # 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 # 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 # 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 : # that should be defined before calling this helper :
# ```
# __PATH__ by $path_url # __PATH__ by $path_url
# __NAME__ by $app # __NAME__ by $app
# __NAMETOCHANGE__ by $app # __NAMETOCHANGE__ by $app
@ -286,33 +319,34 @@ ynh_local_curl () {
# __FINALPATH__ by $final_path # __FINALPATH__ by $final_path
# __PHPVERSION__ by $YNH_PHP_VERSION # __PHPVERSION__ by $YNH_PHP_VERSION
# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH # __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH
# # ```
# And any dynamic variables that should be defined before calling this helper like: # And any dynamic variables that should be defined before calling this helper like:
# ```
# __DOMAIN__ by $domain # __DOMAIN__ by $domain
# __APP__ by $app # __APP__ by $app
# __VAR_1__ by $var_1 # __VAR_1__ by $var_1
# __VAR_2__ by $var_2 # __VAR_2__ by $var_2
# ```
# #
# The helper will verify the checksum and backup the destination file # The helper will verify the checksum and backup the destination file
# if it's different before applying the new template. # if it's different before applying the new template.
#
# And it will calculate and store the destination file checksum # And it will calculate and store the destination file checksum
# into the app settings when configuration is done. # into the app settings when configuration is done.
# #
# Requires YunoHost version 4.1.0 or higher. # Requires YunoHost version 4.1.0 or higher.
ynh_add_config () { ynh_add_config() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=tdv local legacy_args=tdv
local -A args_array=( [t]=template= [d]=destination= ) local -A args_array=([t]=template= [d]=destination=)
local template local template
local destination local destination
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local template_path local template_path
if [ -f "../conf/$template" ]; then if [ -f "$YNH_APP_BASEDIR/conf/$template" ]; then
template_path="../conf/$template" template_path="$YNH_APP_BASEDIR/conf/$template"
elif [ -f "../settings/conf/$template" ]; then
template_path="../settings/conf/$template"
elif [ -f "$template" ]; then elif [ -f "$template" ]; then
template_path=$template template_path=$template
else else
@ -321,8 +355,17 @@ ynh_add_config () {
ynh_backup_if_checksum_is_different --file="$destination" ynh_backup_if_checksum_is_different --file="$destination"
cp "$template_path" "$destination" # Make sure to set the permissions before we copy the file
chown root: "$destination" # 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_replace_vars --file="$destination"
@ -353,17 +396,16 @@ ynh_add_config () {
# __VAR_2__ by $var_2 # __VAR_2__ by $var_2
# #
# Requires YunoHost version 4.1.0 or higher. # Requires YunoHost version 4.1.0 or higher.
ynh_replace_vars () { ynh_replace_vars() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=([f]=file=)
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# Replace specific YunoHost variables # Replace specific YunoHost variables
if test -n "${path_url:-}" if test -n "${path_url:-}"; then
then
# path_url_slash_less is path_url, or a blank value if path_url is only '/' # path_url_slash_less is path_url, or a blank value if path_url is only '/'
local path_url_slash_less=${path_url%/} 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_slash_less/" --target_file="$file"
@ -387,20 +429,23 @@ ynh_replace_vars () {
# Replace others variables # Replace others variables
# List other unique (__ __) variables in $file # List other unique (__ __) variables in $file
local uniques_vars=( $(grep -o '__[A-Z0-9_]*__' $file | sort --unique | sed "s@__\([^.]*\)__@\L\1@g" )) 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 # Do the replacement
local delimit=@ local delimit=@
for one_var in "${uniques_vars[@]}" for one_var in "${uniques_vars[@]}"; do
do
# Validate that one_var is indeed defined # Validate that one_var is indeed defined
# Explanation for the weird '+x' syntax: https://stackoverflow.com/a/13864829 # -v checks if the variable is defined, for example:
test -n "${one_var+x}" || ynh_die --message="Variable \$$one_var wasn't initialized when trying to replace __${one_var^^}__ in $file" # -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 # Escape delimiter in match/replace string
match_string="__${one_var^^}__" match_string="__${one_var^^}__"
match_string=${match_string//${delimit}/"\\${delimit}"} match_string=${match_string//${delimit}/"\\${delimit}"}
replace_string="${!one_var}" replace_string="${!one_var}"
replace_string=${replace_string//\\/\\\\}
replace_string=${replace_string//${delimit}/"\\${delimit}"} 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) # Actually replace (sed is used instead of ynh_replace_string to avoid triggering an epic amount of debug logs)
@ -408,6 +453,202 @@ ynh_replace_vars () {
done 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 # Render templates with Jinja2
# #
# [internal] # [internal]
@ -425,7 +666,7 @@ ynh_render_template() {
# Taken from https://stackoverflow.com/a/35009576 # Taken from https://stackoverflow.com/a/35009576
python3 -c 'import os, sys, jinja2; sys.stdout.write( python3 -c 'import os, sys, jinja2; sys.stdout.write(
jinja2.Template(sys.stdin.read() jinja2.Template(sys.stdin.read()
).render(os.environ));' < $template_path > $output_path ).render(os.environ));' <$template_path >$output_path
} }
# Fetch the Debian release codename # Fetch the Debian release codename
@ -434,7 +675,7 @@ ynh_render_template() {
# | ret: The Debian release codename (i.e. jessie, stretch, ...) # | ret: The Debian release codename (i.e. jessie, stretch, ...)
# #
# Requires YunoHost version 2.7.12 or higher. # Requires YunoHost version 2.7.12 or higher.
ynh_get_debian_release () { ynh_get_debian_release() {
echo $(lsb_release --codename --short) echo $(lsb_release --codename --short)
} }
@ -458,80 +699,83 @@ properly with chmod/chown."
echo $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 # Remove a file or a directory securely
# #
# usage: ynh_secure_remove --file=path_to_remove # usage: ynh_secure_remove --file=path_to_remove
# | arg: -f, --file= - File or directory to remove # | arg: -f, --file= - File or directory to remove
# #
# Requires YunoHost version 2.6.4 or higher. # Requires YunoHost version 2.6.4 or higher.
ynh_secure_remove () { ynh_secure_remove() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f local legacy_args=f
local -A args_array=( [f]=file= ) local -A args_array=([f]=file=)
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
set +o xtrace # set +x
local forbidden_path=" \ if [ $# -ge 2 ]; then
/var/www \
/home/yunohost.app"
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." 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 fi
if [[ -z "$file" ]] if [[ -z "$file" ]]; then
then
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring." ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
elif [[ "$forbidden_path" =~ "$file" \ elif [[ ! -e $file ]]; then
# Match all paths or subpaths in $forbidden_path
|| "$file" =~ ^/[[:alnum:]]+$ \
# Match all first level paths from / (Like /var, /root, etc...)
|| "${file:${#file}-1}" = "/" ]]
# Match if the path finishes by /. Because it seems there is an empty variable
then
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
elif [ -e "$file" ]
then
rm --recursive "$file"
else
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist." 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 fi
set -o xtrace # set -x
} }
# Extract a key from a plain command output # Extract a key from a plain command output
# #
# [internal] # [internal]
# #
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail # (Deprecated, use --output-as json and jq instead)
#
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
# | ret: string - the key's value
#
# Requires YunoHost version 2.2.4 or higher.
ynh_get_plain_key() { ynh_get_plain_key() {
local prefix="#" local prefix="#"
local founded=0 local found=0
# We call this key_ so that it's not caught as # We call this key_ so that it's not caught as
# an info to be redacted by the core # an info to be redacted by the core
local key_=$1 local key_=$1
shift shift
while read line while read line; do
do if [[ "$found" == "1" ]]; then
if [[ "$founded" == "1" ]]
then
[[ "$line" =~ ^${prefix}[^#] ]] && return [[ "$line" =~ ^${prefix}[^#] ]] && return
echo $line echo $line
elif [[ "$line" =~ ^${prefix}${key_}$ ]] elif [[ "$line" =~ ^${prefix}${key_}$ ]]; then
then if [[ -n "${1:-}" ]]; then
if [[ -n "${1:-}" ]]
then
prefix+="#" prefix+="#"
key_=$1 key_=$1
shift shift
else else
founded=1 found=1
fi fi
fi fi
done done
@ -545,10 +789,10 @@ ynh_get_plain_key() {
# | ret: the value associate to that key # | ret: the value associate to that key
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_read_manifest () { ynh_read_manifest() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=mk local legacy_args=mk
local -A args_array=( [m]=manifest= [k]=manifest_key= ) local -A args_array=([m]=manifest= [k]=manifest_key=)
local manifest local manifest
local manifest_key local manifest_key
# Manage arguments with getopts # Manage arguments with getopts
@ -556,35 +800,35 @@ ynh_read_manifest () {
if [ ! -e "$manifest" ]; then if [ ! -e "$manifest" ]; then
# If the manifest isn't found, try the common place for backup and restore script. # If the manifest isn't found, try the common place for backup and restore script.
manifest="../settings/manifest.json" manifest="$YNH_APP_BASEDIR/manifest.json"
fi fi
jq ".$manifest_key" "$manifest" --raw-output jq ".$manifest_key" "$manifest" --raw-output
} }
# Read the upstream version from the manifest, or from the env variable $YNH_APP_MANIFEST_VERSION if not given # Read the upstream version from the manifest or `$YNH_APP_MANIFEST_VERSION`
# #
# usage: ynh_app_upstream_version [--manifest="manifest.json"] # usage: ynh_app_upstream_version [--manifest="manifest.json"]
# | arg: -m, --manifest= - Path of the manifest to read # | arg: -m, --manifest= - Path of the manifest to read
# | ret: the version number of the upstream app # | ret: the version number of the upstream app
# #
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion> # If the `manifest` is not specified, the envvar `$YNH_APP_MANIFEST_VERSION` will be used.
# For example : 4.3-2~ynh3 #
# This include the number before ~ynh # The version number in the manifest is defined by `<upstreamversion>~ynh<packageversion>`.
# In the last example it return 4.3-2 #
# 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. # Requires YunoHost version 3.5.0 or higher.
ynh_app_upstream_version () { ynh_app_upstream_version() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=m local legacy_args=m
local -A args_array=( [m]=manifest= ) local -A args_array=([m]=manifest=)
local manifest local manifest
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
manifest="${manifest:-}" manifest="${manifest:-}"
if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]]; if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]]; then
then
version_key_=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version") version_key_=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
else else
version_key_=$YNH_APP_MANIFEST_VERSION version_key_=$YNH_APP_MANIFEST_VERSION
@ -599,16 +843,15 @@ ynh_app_upstream_version () {
# | arg: -m, --manifest= - Path of the manifest to read # | arg: -m, --manifest= - Path of the manifest to read
# | ret: the version number of the package # | ret: the version number of the package
# #
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion> # The version number in the manifest is defined by `<upstreamversion>~ynh<packageversion>`.
# For example : 4.3-2~ynh3 #
# This include the number after ~ynh # For example, if the manifest contains `4.3-2~ynh3` the function will return `3`
# In the last example it return 3
# #
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_app_package_version () { ynh_app_package_version() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=m local legacy_args=m
local -A args_array=( [m]=manifest= ) local -A args_array=([m]=manifest=)
local manifest local manifest
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -619,24 +862,21 @@ ynh_app_package_version () {
# Checks the app version to upgrade with the existing app version and returns: # Checks the app version to upgrade with the existing app version and returns:
# #
# - UPGRADE_PACKAGE if only the YunoHost package has changed # usage: ynh_check_app_version_changed
# - UPGRADE_APP otherwise # | 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 # This helper should be used to avoid an upgrade of an app, or the upstream part
# of it, when it's not needed # of it, when it's not needed
# #
# To force an upgrade, even if the package is up to date, # You can force an upgrade, even if the package is up to date, with the `--force` (or `-F`) argument :
# you have to use the parameter --force (or -F). # ```
# example: sudo yunohost app upgrade MyApp --force # sudo yunohost app upgrade <appname> --force
# # ```
# usage: ynh_check_app_version_changed
#
# Requires YunoHost version 3.5.0 or higher. # Requires YunoHost version 3.5.0 or higher.
ynh_check_app_version_changed () { ynh_check_app_version_changed() {
local return_value=${YNH_APP_UPGRADE_TYPE} local return_value=${YNH_APP_UPGRADE_TYPE}
if [ "$return_value" == "UPGRADE_FULL" ] || [ "$return_value" == "UPGRADE_FORCED" ] || [ "$return_value" == "DOWNGRADE_FORCED" ] if [ "$return_value" == "UPGRADE_FULL" ] || [ "$return_value" == "UPGRADE_FORCED" ] || [ "$return_value" == "DOWNGRADE_FORCED" ]; then
then
return_value="UPGRADE_APP" return_value="UPGRADE_APP"
fi fi
@ -644,29 +884,28 @@ ynh_check_app_version_changed () {
} }
# Compare the current package version against another version given as an argument. # Compare the current package version against another version given as an argument.
# This is really useful when we need to do some actions only for some old package versions. #
# 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 # example: ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1
# This example will check if the installed version is lower than (lt) the version 2.3.2~ynh1
# #
# Generally you might probably use it as follow in the upgrade script # 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 # if ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1
# then # then
# # Do something that is needed for the package version older than 2.3.2~ynh1 # # Do something that is needed for the package version older than 2.3.2~ynh1
# fi # fi
# # ```
# usage: ynh_compare_current_package_version --comparison lt|le|eq|ne|ge|gt
# | 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)
#
# Return 0 if the evaluation is true. 1 if false.
# #
# Requires YunoHost version 3.8.0 or higher. # Requires YunoHost version 3.8.0 or higher.
ynh_compare_current_package_version() { ynh_compare_current_package_version() {
local legacy_args=cv local legacy_args=cv
declare -Ar args_array=( [c]=comparison= [v]=version= ) declare -Ar args_array=([c]=comparison= [v]=version=)
local version local version
local comparison local comparison
# Manage arguments with getopts # Manage arguments with getopts
@ -675,16 +914,47 @@ ynh_compare_current_package_version() {
local current_version=$YNH_APP_CURRENT_VERSION local current_version=$YNH_APP_CURRENT_VERSION
# Check the syntax of the versions # Check the syntax of the versions
if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]] if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]]; then
then
ynh_die --message="Invalid argument for version." ynh_die --message="Invalid argument for version."
fi fi
# Check validity of the comparator # Check validity of the comparator
if [[ ! $comparison =~ (lt|le|eq|ne|ge|gt) ]]; then if [[ ! $comparison =~ (lt|le|eq|ne|ge|gt) ]]; then
ynh_die --message="Invialid comparator must be : lt, le, eq, ne, ge, gt" ynh_die --message="Invalid comparator must be : lt, le, eq, ne, ge, gt"
fi fi
# Return the return value of dpkg --compare-versions # Return the return value of dpkg --compare-versions
dpkg --compare-versions $current_version $comparison $version 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
}

1
data/hooks/backup/05-conf_ldap Executable file → Normal file
View file

@ -11,7 +11,6 @@ backup_dir="${1}/conf/ldap"
# Backup the configuration # Backup the configuration
ynh_backup "/etc/ldap/ldap.conf" "${backup_dir}/ldap.conf" ynh_backup "/etc/ldap/ldap.conf" "${backup_dir}/ldap.conf"
ynh_backup "/etc/ldap/slapd.ldif" "${backup_dir}/slapd.ldif"
slapcat -b cn=config -l "${backup_dir}/cn=config.master.ldif" slapcat -b cn=config -l "${backup_dir}/cn=config.master.ldif"
# Backup the database # Backup the database

View file

@ -1,17 +0,0 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/ssh"
# Backup the configuration
if [ -d /etc/ssh/ ]; then
ynh_backup "/etc/ssh" "$backup_dir"
else
echo "SSH is not installed"
fi

0
data/hooks/backup/17-data_home Executable file → Normal file
View file

View file

@ -0,0 +1,17 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/data/multimedia"
if [ -e "/home/yunohost.multimedia/.nobackup" ]; then
exit 0
fi
# Backup multimedia directory
ynh_backup --src_path="/home/yunohost.multimedia" --dest_path="${backup_dir}" --is_big --not_mandatory

View file

@ -1,13 +0,0 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/ynh/firewall"
# Backup the configuration
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"

View file

@ -0,0 +1,18 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/ynh"
# Backup the configuration
ynh_backup "/etc/yunohost/firewall.yml" "${backup_dir}/firewall.yml"
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"
ynh_backup "/etc/yunohost/domains" "${backup_dir}/domains"
[ ! -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/dkim" ] || ynh_backup "/etc/dkim" "${backup_dir}/dkim"

0
data/hooks/backup/21-conf_ynh_certs Executable file → Normal file
View file

View file

@ -1,9 +0,0 @@
#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/dkim"
mkdir -p "$YNH_CWD"
cd "$YNH_CWD"
ynh_backup --src_path="/etc/dkim"

0
data/hooks/backup/23-data_mail Executable file → Normal file
View file

View file

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

View file

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

View file

@ -1,13 +0,0 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/nginx"
# Backup the configuration
ynh_backup "/etc/nginx/conf.d" "$backup_dir"

View file

@ -1,15 +0,0 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/cron"
# Backup the configuration
for f in $(ls -1B /etc/cron.d/yunohost* 2> /dev/null); do
ynh_backup "$f" "${backup_dir}/${f##*/}"
done

View file

@ -1,13 +0,0 @@
#!/bin/bash
# Exit hook on subcommand error or unset variable
set -eu
# Source YNH helpers
source /usr/share/yunohost/helpers
# Backup destination
backup_dir="${1}/conf/ynh"
# Backup the configuration
ynh_backup "/etc/yunohost/current_host" "${backup_dir}/current_host"

View file

@ -1,11 +0,0 @@
#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/ynh/dyndns"
mkdir -p $YNH_CWD
cd "$YNH_CWD"
# Backup the configuration
ynh_exec_warn_less ynh_backup --src_path="/etc/yunohost/dyndns" --not_mandatory
ynh_exec_warn_less ynh_backup --src_path="/etc/cron.d/yunohost-dyndns" --not_mandatory

View file

@ -0,0 +1,17 @@
#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/manually_modified_files"
mkdir -p "$YNH_CWD"
cd "$YNH_CWD"
yunohost tools shell -c "from yunohost.regenconf import manually_modified_files; print('\n'.join(manually_modified_files()))" >./manually_modified_files_list
ynh_backup --src_path="./manually_modified_files_list"
for file in $(cat ./manually_modified_files_list); do
[[ -e $file ]] && ynh_backup --src_path="$file"
done
ynh_backup --src_path="/etc/ssowat/conf.json.persistent"

View file

@ -2,8 +2,6 @@
set -e set -e
services_path="/etc/yunohost/services.yml"
do_init_regen() { do_init_regen() {
if [[ $EUID -ne 0 ]]; then if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2 echo "You must be root to run this script" 1>&2
@ -16,11 +14,9 @@ do_init_regen() {
# set default current_host # set default current_host
[[ -f /etc/yunohost/current_host ]] \ [[ -f /etc/yunohost/current_host ]] \
|| echo "yunohost.org" > /etc/yunohost/current_host || echo "yunohost.org" >/etc/yunohost/current_host
# copy default services and firewall # copy default services and firewall
[[ -f $services_path ]] \
|| cp services.yml "$services_path"
[[ -f /etc/yunohost/firewall.yml ]] \ [[ -f /etc/yunohost/firewall.yml ]] \
|| cp firewall.yml /etc/yunohost/firewall.yml || cp firewall.yml /etc/yunohost/firewall.yml
@ -39,17 +35,35 @@ do_init_regen() {
mkdir -p /home/yunohost.app mkdir -p /home/yunohost.app
chmod 755 /home/yunohost.app chmod 755 /home/yunohost.app
# Domain settings
mkdir -p /etc/yunohost/domains
chmod 700 /etc/yunohost/domains
# 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 admin:root once admin user 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'
chmod 644 /etc/ssowat/conf.json.persistent chmod 644 /etc/ssowat/conf.json.persistent
chown root:root /etc/ssowat/conf.json.persistent chown root:root /etc/ssowat/conf.json.persistent
# Empty service conf
touch /etc/yunohost/services.yml
mkdir -p /var/cache/yunohost/repo mkdir -p /var/cache/yunohost/repo
chown root:root /var/cache/yunohost
chmod 700 /var/cache/yunohost
cp yunoprompt.service /etc/systemd/system/yunoprompt.service
cp dpkg-origins /etc/dpkg/origins/yunohost
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
readlink -f /etc/dpkg/origins/default | grep -q debian \
&& rm -f /etc/dpkg/origins/default \
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
} }
do_pre_regen() { do_pre_regen() {
@ -57,35 +71,44 @@ do_pre_regen() {
cd /usr/share/yunohost/templates/yunohost cd /usr/share/yunohost/templates/yunohost
# update services.yml # Legacy code that can be removed once on bullseye
if [[ -f $services_path ]]; then touch /etc/yunohost/services.yml
tmp_services_path="${services_path}-tmp" yunohost tools shell -c "from yunohost.service import _get_services, _save_services; _save_services(_get_services())"
new_services_path="${services_path}-new"
cp "$services_path" "$tmp_services_path" mkdir -p $pending_dir/etc/systemd/system
_update_services "$new_services_path" || { mkdir -p $pending_dir/etc/cron.d/
mv "$tmp_services_path" "$services_path" mkdir -p $pending_dir/etc/cron.daily/
exit 1
}
if [[ -f $new_services_path ]]; then
# replace services.yml with new one
mv "$new_services_path" "$services_path"
mv "$tmp_services_path" "${services_path}-old"
else
rm -f "$tmp_services_path"
fi
else
cp services.yml /etc/yunohost/services.yml
fi
# add cron job for diagnosis to be ran at 7h and 19h + a random delay between # add cron job for diagnosis to be ran at 7h and 19h + a random delay between
# 0 and 20min, meant to avoid every instances running their diagnosis at # 0 and 20min, meant to avoid every instances running their diagnosis at
# exactly the same time, which may overload the diagnosis server. # exactly the same time, which may overload the diagnosis server.
mkdir -p $pending_dir/etc/cron.d/ cat >$pending_dir/etc/cron.d/yunohost-diagnosis <<EOF
cat > $pending_dir/etc/cron.d/yunohost-diagnosis << EOF
SHELL=/bin/bash SHELL=/bin/bash
0 7,19 * * * root : YunoHost Automatic Diagnosis; sleep \$((RANDOM\\%1200)); yunohost diagnosis run --email > /dev/null 2>/dev/null || echo "Running the automatic diagnosis failed miserably" 0 7,19 * * * root : YunoHost Automatic Diagnosis; sleep \$((RANDOM\\%1200)); yunohost diagnosis run --email > /dev/null 2>/dev/null || echo "Running the automatic diagnosis failed miserably"
EOF EOF
# Cron job that upgrade the app list everyday
cat >$pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog <<EOF
#!/bin/bash
(sleep \$((RANDOM%3600)); yunohost tools update --apps > /dev/null) &
EOF
# Cron job that renew lets encrypt certificates if there's any that needs renewal
cat >$pending_dir/etc/cron.daily/yunohost-certificate-renew <<EOF
#!/bin/bash
yunohost domain cert renew --email
EOF
# 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
# - 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*.private 2>/dev/null; then
cat >$pending_dir/etc/cron.d/yunohost-dyndns <<EOF
SHELL=/bin/bash
*/10 * * * * root : YunoHost DynDNS update; sleep \$((RANDOM\\%60)); test -e /var/run/moulinette_yunohost.lock || yunohost dyndns update >> /dev/null
EOF
fi
# legacy stuff to avoid yunohost reporting etckeeper as manually modified # legacy stuff to avoid yunohost reporting etckeeper as manually modified
# (this make sure that the hash is null / file is flagged as to-delete) # (this make sure that the hash is null / file is flagged as to-delete)
mkdir -p $pending_dir/etc/etckeeper mkdir -p $pending_dir/etc/etckeeper
@ -97,17 +120,38 @@ EOF
[Unit] [Unit]
ConditionCapability=CAP_SYS_TIME ConditionCapability=CAP_SYS_TIME
ConditionVirtualization=!container ConditionVirtualization=!container
" > ${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf " >${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf
# 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/
cat > ${pending_dir}/etc/systemd/system/nftables.service.d/ynh-override.conf << EOF cat >${pending_dir}/etc/systemd/system/nftables.service.d/ynh-override.conf <<EOF
[Unit] [Unit]
# yunohost-firewall and nftables conflict with each other # yunohost-firewall and nftables conflict with each other
Conflicts=yunohost-firewall.service Conflicts=yunohost-firewall.service
ConditionFileIsExecutable=!/etc/init.d/yunohost-firewall ConditionFileIsExecutable=!/etc/init.d/yunohost-firewall
ConditionPathExists=!/etc/systemd/system/multi-user.target.wants/yunohost-firewall.service ConditionPathExists=!/etc/systemd/system/multi-user.target.wants/yunohost-firewall.service
EOF EOF
# Don't suspend computer on LidSwitch
mkdir -p ${pending_dir}/etc/systemd/logind.conf.d/
cat >${pending_dir}/etc/systemd/logind.conf.d/ynh-override.conf <<EOF
[Login]
HandleLidSwitch=ignore
HandleLidSwitchDocked=ignore
HandleLidSwitchExternalPower=ignore
EOF
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
else
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
fi
mkdir -p ${pending_dir}/etc/dpkg/origins/
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
} }
do_post_regen() { do_post_regen() {
@ -117,6 +161,12 @@ do_post_regen() {
# Enfore permissions # # Enfore permissions #
###################### ######################
chmod 750 /home/admin
chmod 750 /home/yunohost.conf
chmod 750 /home/yunohost.backup
chmod 750 /home/yunohost.backup/archives
chown root:root /home/yunohost.conf
chown admin:root /home/yunohost.backup
chown admin:root /home/yunohost.backup/archives chown admin:root /home/yunohost.backup/archives
# Certs # Certs
@ -126,6 +176,27 @@ do_post_regen() {
find /etc/yunohost/certs/ -type f -exec chmod 640 {} \; find /etc/yunohost/certs/ -type f -exec chmod 640 {} \;
find /etc/yunohost/certs/ -type d -exec chmod 750 {} \; find /etc/yunohost/certs/ -type d -exec chmod 750 {} \;
find /etc/cron.*/yunohost-* -type f -exec chmod 755 {} \;
find /etc/cron.d/yunohost-* -type f -exec chmod 644 {} \;
find /etc/cron.*/yunohost-* -type f -exec chown root:root {} \;
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/log/nginx
setfacl -m g:all_users:--- /etc/yunohost
setfacl -m g:all_users:--- /etc/ssowat
for USER in $(yunohost user list --quiet --output-as json | jq -r '.users | .[] | .username'); do
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
done
# Domain settings
mkdir -p /etc/yunohost/domains
# Misc configuration / state files # Misc configuration / state files
chown root:root $(ls /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql} 2>/dev/null) 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)
@ -133,88 +204,35 @@ do_post_regen() {
# Apps folder, custom hooks folder # Apps folder, custom hooks folder
[[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d) [[ ! -e /etc/yunohost/hooks.d ]] || (chown root /etc/yunohost/hooks.d && chmod 700 /etc/yunohost/hooks.d)
[[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps) [[ ! -e /etc/yunohost/apps ]] || (chown root /etc/yunohost/apps && chmod 700 /etc/yunohost/apps)
[[ ! -e /etc/yunohost/domains ]] || (chown root /etc/yunohost/domains && chmod 700 /etc/yunohost/domains)
# Create ssh.app and sftp.app groups if they don't exist yet
grep -q '^ssh.app:' /etc/group || groupadd ssh.app
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
# Propagates changes in systemd service config overrides # Propagates changes in systemd service config overrides
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || { systemctl daemon-reload; systemctl restart ntp; } [[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
systemctl daemon-reload
systemctl restart ntp
}
[[ ! "$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" ]] || systemctl daemon-reload
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
systemctl daemon-reload
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
systemctl $action yunoprompt --quiet --now
fi
if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]; then
systemctl daemon-reload
action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
systemctl $action proc-hidepid --quiet --now
fi
# Change dpkg vendor
# see https://wiki.debian.org/Derivatives/Guidelines#Vendor
readlink -f /etc/dpkg/origins/default | grep -q debian \
&& rm -f /etc/dpkg/origins/default \
&& ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
} }
_update_services() { do_$1_regen ${@:2}
python3 - << EOF
import yaml
with open('services.yml') as f:
new_services = yaml.load(f)
with open('/etc/yunohost/services.yml') as f:
services = yaml.load(f) or {}
updated = False
for service, conf in new_services.items():
# remove service with empty conf
if conf is None:
if service in services:
print("removing '{0}' from services".format(service))
del services[service]
updated = True
# add new service
elif not services.get(service, None):
print("adding '{0}' to services".format(service))
services[service] = conf
updated = True
# update service conf
else:
conffiles = services[service].pop('conffiles', {})
# status need to be removed
if "status" not in conf and "status" in services[service]:
print("update '{0}' service status access".format(service))
del services[service]["status"]
updated = True
if services[service] != conf:
print("update '{0}' service".format(service))
services[service].update(conf)
updated = True
if conffiles:
services[service]['conffiles'] = conffiles
# Remove legacy /var/log/daemon.log and /var/log/syslog from log entries
# because they are too general. Instead, now the journalctl log is
# returned by default which is more relevant.
if "log" in services[service]:
if services[service]["log"] in ["/var/log/syslog", "/var/log/daemon.log"]:
del services[service]["log"]
if updated:
with open('/etc/yunohost/services.yml-new', 'w') as f:
yaml.safe_dump(services, f, default_flow_style=False)
EOF
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -23,7 +23,7 @@ regen_local_ca() {
# (Update the serial so that it's specific to this very instance) # (Update the serial so that it's specific to this very instance)
# N.B. : the weird RANDFILE thing comes from: # N.B. : the weird RANDFILE thing comes from:
# https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean # https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
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 /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf cp /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf
@ -48,12 +48,10 @@ regen_local_ca() {
popd popd
} }
do_init_regen() { do_init_regen() {
LOGFILE=/tmp/yunohost-ssl-init LOGFILE=/tmp/yunohost-ssl-init
echo "" > $LOGFILE echo "" >$LOGFILE
chown root:root $LOGFILE chown root:root $LOGFILE
chmod 640 $LOGFILE chmod 640 $LOGFILE
@ -112,8 +110,7 @@ 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)
if [[ "$current_local_ca_domain" != "$main_domain" ]] if [[ "$current_local_ca_domain" != "$main_domain" ]]; then
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/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem ln -sf /etc/yunohost/certs/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
@ -121,23 +118,4 @@ do_post_regen() {
fi fi
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -25,7 +25,7 @@ do_pre_regen() {
# Support different strategy for security configurations # Support different strategy for security configurations
export compatibility="$(yunohost settings get 'security.ssh.compatibility')" export compatibility="$(yunohost settings get 'security.ssh.compatibility')"
export port="$(yunohost settings get 'security.ssh.port')"
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"
@ -48,20 +48,4 @@ do_post_regen() {
systemctl restart ssh systemctl restart ssh
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -2,7 +2,10 @@
set -e set -e
tmp_backup_dir_file="/tmp/slapd-backup-dir.txt" tmp_backup_dir_file="/root/slapd-backup-dir.txt"
config="/usr/share/yunohost/templates/slapd/config.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
@ -12,16 +15,12 @@ do_init_regen() {
do_pre_regen "" do_pre_regen ""
systemctl daemon-reload
systemctl restart slapd
# Drop current existing slapd data # Drop current existing slapd data
rm -rf /var/backups/*.ldapdb rm -rf /var/backups/*.ldapdb
rm -rf /var/backups/slapd-* rm -rf /var/backups/slapd-*
debconf-set-selections << EOF debconf-set-selections <<EOF
slapd slapd/password1 password yunohost slapd slapd/password1 password yunohost
slapd slapd/password2 password yunohost slapd slapd/password2 password yunohost
slapd slapd/domain string yunohost.org slapd slapd/domain string yunohost.org
@ -36,20 +35,37 @@ EOF
DEBIAN_FRONTEND=noninteractive dpkg-reconfigure slapd -u DEBIAN_FRONTEND=noninteractive dpkg-reconfigure slapd -u
# Regen conf
_regenerate_slapd_conf
# Enforce permissions # Enforce permissions
chown root:openldap /etc/ldap/slapd.ldif
chown -R openldap:openldap /etc/ldap/schema/ chown -R openldap:openldap /etc/ldap/schema/
usermod -aG ssl-cert openldap usermod -aG ssl-cert openldap
# (Re-)init data according to default ldap entries
echo ' Initializing LDAP with YunoHost DB structure'
rm -rf /etc/ldap/slapd.d
mkdir -p /etc/ldap/slapd.d
slapadd -F /etc/ldap/slapd.d -b cn=config -l "$config" 2>&1 \
| grep -v "none elapsed\|Closing DB" || true
chown -R openldap: /etc/ldap/slapd.d
rm -rf /var/lib/ldap
mkdir -p /var/lib/ldap
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org -l "$db_init" 2>&1 \
| grep -v "none elapsed\|Closing DB" || true
chown -R openldap: /var/lib/ldap
nscd -i group || true
nscd -i passwd || true
systemctl restart slapd systemctl restart slapd
# (Re-)init data according to ldap_scheme.yaml # We don't use mkhomedir_helper because 'admin' may not be recognized
# when this script is ran in a chroot (e.g. ISO install)
yunohost tools shell -c "from yunohost.tools import tools_ldapinit; tools_ldapinit()" # 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() {
@ -59,7 +75,7 @@ _regenerate_slapd_conf() {
# so we use a temporary directory slapd_new.d # so we use a temporary directory slapd_new.d
rm -Rf /etc/ldap/slapd_new.d rm -Rf /etc/ldap/slapd_new.d
mkdir /etc/ldap/slapd_new.d mkdir /etc/ldap/slapd_new.d
slapadd -n0 -l /etc/ldap/slapd.ldif -F /etc/ldap/slapd_new.d/ 2>&1 \ slapadd -b cn=config -l "$config" -F /etc/ldap/slapd_new.d/ 2>&1 \
| grep -v "none elapsed\|Closing DB" || true | grep -v "none elapsed\|Closing DB" || true
# Actual validation (-Q is for quiet, -u is for dry-run) # Actual validation (-Q is for quiet, -u is for dry-run)
slaptest -Q -u -F /etc/ldap/slapd_new.d slaptest -Q -u -F /etc/ldap/slapd_new.d
@ -80,12 +96,12 @@ do_pre_regen() {
# Define if we need to migrate from hdb to mdb # Define if we need to migrate from hdb to mdb
curr_backend=$(grep '^database' /etc/ldap/slapd.conf 2>/dev/null | awk '{print $2}') curr_backend=$(grep '^database' /etc/ldap/slapd.conf 2>/dev/null | awk '{print $2}')
if [ -e /etc/ldap/slapd.conf ] && [ -n "$curr_backend" ] && \ if [ -e /etc/ldap/slapd.conf ] && [ -n "$curr_backend" ] \
[ $curr_backend != 'mdb' ]; then && [ $curr_backend != 'mdb' ]; then
backup_dir="/var/backups/dc=yunohost,dc=org-${curr_backend}-$(date +%s)" backup_dir="/var/backups/dc=yunohost,dc=org-${curr_backend}-$(date +%s)"
mkdir -p "$backup_dir" mkdir -p "$backup_dir"
slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif" slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif"
echo "$backup_dir" > "$tmp_backup_dir_file" echo "$backup_dir" >"$tmp_backup_dir_file"
fi fi
# create needed directories # create needed directories
@ -101,7 +117,7 @@ do_pre_regen() {
cd /usr/share/yunohost/templates/slapd cd /usr/share/yunohost/templates/slapd
# copy configuration files # copy configuration files
cp -a ldap.conf slapd.ldif "$ldap_dir" cp -a ldap.conf "$ldap_dir"
cp -a sudo.ldif mailserver.ldif permission.ldif "$schema_dir" cp -a sudo.ldif mailserver.ldif permission.ldif "$schema_dir"
mkdir -p ${pending_dir}/etc/systemd/system/slapd.service.d/ mkdir -p ${pending_dir}/etc/systemd/system/slapd.service.d/
@ -117,21 +133,34 @@ do_post_regen() {
echo "Enforce permissions on ldap/slapd directories and certs ..." echo "Enforce permissions on ldap/slapd directories and certs ..."
# penldap user should be in the ssl-cert group to let it access the certificate for TLS # penldap user should be in the ssl-cert group to let it access the certificate for TLS
usermod -aG ssl-cert openldap usermod -aG ssl-cert openldap
chown root:openldap /etc/ldap/slapd.ldif
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/
# 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$" if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$"; then
then
systemctl daemon-reload systemctl daemon-reload
systemctl restart slapd systemctl restart slapd
sleep 3
fi
# For some reason, old setups don't have the admins group defined...
if ! slapcat | grep -q 'cn=admins,ou=groups,dc=yunohost,dc=org'; then
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org <<< \
"dn: cn=admins,ou=groups,dc=yunohost,dc=org
cn: admins
gidNumber: 4001
memberUid: admin
objectClass: posixGroup
objectClass: top"
chown -R openldap: /var/lib/ldap
systemctl restart slapd
nscd -i group
fi fi
[ -z "$regen_conf_files" ] && exit 0 [ -z "$regen_conf_files" ] && exit 0
# regenerate LDAP config directory from slapd.conf # regenerate LDAP config directory from slapd.conf
echo "Regenerate LDAP config directory from slapd.ldif" echo "Regenerate LDAP config directory from config.ldif"
_regenerate_slapd_conf _regenerate_slapd_conf
# If there's a backup, re-import its data # If there's a backup, re-import its data
@ -147,7 +176,7 @@ do_post_regen() {
su openldap -s "/bin/bash" -c "/usr/sbin/slapindex" su openldap -s "/bin/bash" -c "/usr/sbin/slapindex"
echo "Reloading slapd" echo "Reloading slapd"
service slapd force-reload systemctl force-reload slapd
# on slow hardware/vm this regen conf would exit before the admin user that # 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 # is stored in ldap is available because ldap seems to slow to restart
@ -160,33 +189,10 @@ do_post_regen() {
# wait a maximum time of 5 minutes # wait a maximum time of 5 minutes
# yes, force-reload behave like a restart # yes, force-reload behave like a restart
number_of_wait=0 number_of_wait=0
while ! su admin -c '' && ((number_of_wait < 60)) while ! su admin -c '' && ((number_of_wait < 60)); do
do
sleep 5 sleep 5
((number_of_wait += 1)) ((number_of_wait += 1))
done done
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
apply_config)
do_post_regen /etc/ldap/slapd.ldif
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -22,23 +22,4 @@ do_post_regen() {
|| systemctl restart nslcd || systemctl restart nslcd
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -8,28 +8,24 @@ do_pre_regen() {
mkdir --parents "${pending_dir}/etc/apt/preferences.d" mkdir --parents "${pending_dir}/etc/apt/preferences.d"
packages_to_refuse_from_sury="php php-fpm php-mysql php-xml php-zip php-mbstring php-ldap php-gd php-curl php-bz2 php-json php-sqlite3 php-intl openssl libssl1.1 libssl-dev" packages_to_refuse_from_sury="php php-fpm php-mysql php-xml php-zip php-mbstring php-ldap php-gd php-curl php-bz2 php-json php-sqlite3 php-intl openssl libssl1.1 libssl-dev"
for package in $packages_to_refuse_from_sury for package in $packages_to_refuse_from_sury; do
do
echo " echo "
Package: $package Package: $package
Pin: origin \"packages.sury.org\" Pin: origin \"packages.sury.org\"
Pin-Priority: -1" >> "${pending_dir}/etc/apt/preferences.d/extra_php_version" Pin-Priority: -1" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
done done
echo " echo "
# Yes !
# This is what's preventing you from installing apache2 ! # PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
#
# Maybe take two fucking minutes to realize that if you try to install # You are probably reading this file because you tried to install apache2 or
# apache2, this will break nginx and break the entire YunoHost ecosystem. # bind9. These 2 packages conflict with YunoHost.
# on your server.
# # Installing apache2 will break nginx and break the entire YunoHost ecosystem
# So, *NO* # on your server, therefore don't remove those lines!
# DO NOT do this.
# DO NOT remove these lines. # You have been warned.
#
# I warned you. I WARNED YOU! But did you listen to me?
# Oooooh, noooo. You knew it all, didn't you?
Package: apache2 Package: apache2
Pin: release * Pin: release *
@ -39,14 +35,14 @@ Package: apache2-bin
Pin: release * Pin: release *
Pin-Priority: -1 Pin-Priority: -1
# Also yes, bind9 will conflict with dnsmasq. # Also bind9 will conflict with dnsmasq.
# Same story than for apache2. # Same story as for apache2.
# Don't fucking install it. # Don't install it, don't remove those lines.
Package: bind9 Package: bind9
Pin: release * Pin: release *
Pin-Priority: -1 Pin-Priority: -1
" >> "${pending_dir}/etc/apt/preferences.d/ban_packages" " >>"${pending_dir}/etc/apt/preferences.d/ban_packages"
} }
@ -57,20 +53,4 @@ do_post_regen() {
update-alternatives --set php /usr/bin/php7.3 update-alternatives --set php /usr/bin/php7.3
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -18,13 +18,13 @@ do_pre_regen() {
# install main conf file # install main conf file
cat metronome.cfg.lua \ cat metronome.cfg.lua \
| sed "s/{{ main_domain }}/${main_domain}/g" \ | sed "s/{{ main_domain }}/${main_domain}/g" \
> "${metronome_dir}/metronome.cfg.lua" >"${metronome_dir}/metronome.cfg.lua"
# add domain conf files # add domain conf files
for domain in $YNH_DOMAINS; do for domain in $YNH_DOMAINS; 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"
done done
# remove old domain conf files # remove old domain conf files
@ -52,11 +52,14 @@ do_post_regen() {
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"
# sgid bit allows that file created in that dir will be owned by www-data
# despite the fact that metronome ain't in the www-data group
chmod g+s "/var/xmpp-upload/${domain}/upload" chmod g+s "/var/xmpp-upload/${domain}/upload"
chown -R metronome:www-data "/var/xmpp-upload/${domain}"
done done
# fix some permissions # fix some permissions
[ ! -e '/var/xmpp-upload' ] || chown -R metronome:www-data "/var/xmpp-upload/"
[ ! -e '/var/xmpp-upload' ] || chmod 750 "/var/xmpp-upload/"
# metronome should be in ssl-cert group to let it access SSL certificates # metronome should be in ssl-cert group to let it access SSL certificates
usermod -aG ssl-cert metronome usermod -aG ssl-cert metronome
@ -64,23 +67,7 @@ do_post_regen() {
chown -R metronome: /etc/metronome/conf.d/ chown -R metronome: /etc/metronome/conf.d/
[[ -z "$regen_conf_files" ]] \ [[ -z "$regen_conf_files" ]] \
|| service metronome restart || systemctl restart metronome
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -25,13 +25,21 @@ do_init_regen() {
export compatibility="intermediate" export compatibility="intermediate"
ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc" ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc"
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
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"
mkdir -p $nginx_conf_dir/default.d/ mkdir -p $nginx_conf_dir/default.d/
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/ cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
# Restart nginx if conf looks good, otherwise display error and exit unhappy # Restart nginx if conf looks good, otherwise display error and exit unhappy
nginx -t 2>/dev/null || { nginx -t; exit 1; } nginx -t 2>/dev/null || {
systemctl restart nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } nginx -t
exit 1
}
systemctl restart nginx || {
journalctl --no-pager --lines=10 -u nginx >&2
exit 1
}
exit 0 exit 0
} }
@ -47,15 +55,22 @@ 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
panel_overlay=$(yunohost settings get 'ssowat.panel_overlay.enabled')
if [ "$panel_overlay" == "false" ] || [ "$panel_overlay" == "False" ]; then
echo "#" >"${nginx_conf_dir}/yunohost_panel.conf.inc"
fi
# retrieve variables # retrieve variables
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.redirect_to_https')"
export compatibility="$(yunohost settings get 'security.nginx.compatibility')" export compatibility="$(yunohost settings get 'security.nginx.compatibility')"
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
for domain in $YNH_DOMAINS; do for domain in $YNH_DOMAINS; do
@ -77,6 +92,12 @@ do_pre_regen() {
done done
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.allowlist.enabled)
if [ "$webadmin_allowlist_enabled" == "True" ]; then
export webadmin_allowlist=$(yunohost settings get security.webadmin.allowlist)
fi
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
ynh_render_template "yunohost_api.conf.inc" "${nginx_conf_dir}/yunohost_api.conf.inc"
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
mkdir -p $nginx_conf_dir/default.d/ mkdir -p $nginx_conf_dir/default.d/
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/ cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
@ -116,11 +137,9 @@ do_post_regen() {
# Get rid of legacy lets encrypt snippets # Get rid of legacy lets encrypt snippets
for domain in $YNH_DOMAINS; do for domain in $YNH_DOMAINS; do
# If the legacy letsencrypt / acme-challenge domain-specific snippet is still there # If the legacy letsencrypt / acme-challenge domain-specific snippet is still there
if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ] if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ]; then
then
# And if we're effectively including the new domain-independant snippet now # 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 if grep -q "include /etc/nginx/conf.d/acme-challenge.conf.inc;" /etc/nginx/conf.d/${domain}.conf; then
then
# Delete the old domain-specific snippet # Delete the old domain-specific snippet
rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf
fi fi
@ -128,27 +147,14 @@ do_post_regen() {
done 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; exit 1; } nginx -t 2>/dev/null || {
pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } nginx -t
exit 1
}
pgrep nginx && systemctl reload nginx || {
journalctl --no-pager --lines=10 -u nginx >&2
exit 1
}
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -29,8 +29,7 @@ do_pre_regen() {
export relay_port="" export relay_port=""
export relay_user="" export relay_user=""
export relay_host="$(yunohost settings get 'smtp.relay.host')" export relay_host="$(yunohost settings get 'smtp.relay.host')"
if [ -n "${relay_host}" ] if [ -n "${relay_host}" ]; then
then
relay_port="$(yunohost settings get 'smtp.relay.port')" relay_port="$(yunohost settings get 'smtp.relay.port')"
relay_user="$(yunohost settings get 'smtp.relay.user')" relay_user="$(yunohost settings get 'smtp.relay.user')"
relay_password="$(yunohost settings get 'smtp.relay.password')" relay_password="$(yunohost settings get 'smtp.relay.password')"
@ -42,7 +41,7 @@ do_pre_regen() {
chown postfix ${pending_dir}/etc/postfix chown postfix ${pending_dir}/etc/postfix
chown postfix ${pending_dir}/etc/postfix/sasl_passwd chown postfix ${pending_dir}/etc/postfix/sasl_passwd
cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd cat <<<"[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" >${postfix_dir}/sasl_passwd
postmap ${postfix_dir}/sasl_passwd postmap ${postfix_dir}/sasl_passwd
fi fi
export main_domain export main_domain
@ -52,7 +51,7 @@ do_pre_regen() {
cat postsrsd \ cat postsrsd \
| sed "s/{{ main_domain }}/${main_domain}/g" \ | sed "s/{{ main_domain }}/${main_domain}/g" \
| sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \ | sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \
> "${default_dir}/postsrsd" >"${default_dir}/postsrsd"
# adapt it for IPv4-only hosts # adapt it for IPv4-only hosts
ipv6="$(yunohost settings get 'smtp.allow_ipv6')" ipv6="$(yunohost settings get 'smtp.allow_ipv6')"
@ -69,31 +68,14 @@ do_pre_regen() {
do_post_regen() { do_post_regen() {
regen_conf_files=$1 regen_conf_files=$1
if [ -e /etc/postfix/sasl_passwd ] if [ -e /etc/postfix/sasl_passwd ]; then
then
chmod 750 /etc/postfix/sasl_passwd* chmod 750 /etc/postfix/sasl_passwd*
chown postfix:root /etc/postfix/sasl_passwd* chown postfix:root /etc/postfix/sasl_passwd*
fi fi
[[ -z "$regen_conf_files" ]] \ [[ -z "$regen_conf_files" ]] \
|| { service postfix restart && service postsrsd restart; } || { systemctl restart postfix && systemctl restart postsrsd; }
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -40,8 +40,11 @@ do_post_regen() {
mkdir -p "/etc/dovecot/yunohost.d/post-ext.d" mkdir -p "/etc/dovecot/yunohost.d/post-ext.d"
# create vmail user # create vmail user
id vmail > /dev/null 2>&1 \ id vmail >/dev/null 2>&1 \
|| adduser --system --ingroup mail --uid 500 vmail || adduser --system --ingroup mail --uid 500 vmail --home /var/vmail --no-create-home
# Delete legacy home for vmail that existed in the past but was empty, poluting /home/
[ ! -e /home/vmail ] || rmdir --ignore-fail-on-non-empty /home/vmail
# fix permissions # fix permissions
chown -R vmail:mail /etc/dovecot/global_script chown -R vmail:mail /etc/dovecot/global_script
@ -57,23 +60,7 @@ do_post_regen() {
chown -R vmail:mail /etc/dovecot/global_script chown -R vmail:mail /etc/dovecot/global_script
} }
service dovecot restart systemctl restart dovecot
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -59,20 +59,4 @@ do_post_regen() {
systemctl -q restart rspamd.service systemctl -q restart rspamd.service
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
set -e set -e
MYSQL_PKG="$(dpkg --list | sed -ne 's/^ii \(mariadb-server-[[:digit:].]\+\) .*$/\1/p')"
. /usr/share/yunohost/helpers . /usr/share/yunohost/helpers
do_pre_regen() { do_pre_regen() {
@ -15,11 +14,46 @@ do_pre_regen() {
do_post_regen() { do_post_regen() {
regen_conf_files=$1 regen_conf_files=$1
if [[ ! -d /var/lib/mysql/mysql ]]; then
# dpkg-reconfigure will initialize mysql (if it ain't already)
# It enabled auth_socket for root, so no need to define any root password...
# c.f. : cat /var/lib/dpkg/info/mariadb-server-10.3.postinst | grep install_db -C3
MYSQL_PKG="$(dpkg --list | sed -ne 's/^ii \(mariadb-server-[[:digit:].]\+\) .*$/\1/p')"
dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1
systemctl -q is-active mariadb.service \
|| systemctl start mariadb
sleep 5
echo "" | mysql && echo "Can't connect to mysql using unix_socket auth ... something went wrong during initial configuration of mysql !?" >&2
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.
if [ ! -e /etc/systemd/system/mysql.service ] if [ ! -e /etc/systemd/system/mysql.service ]; then
then
systemctl stop mysql -q systemctl stop mysql -q
systemctl disable mysql -q systemctl disable mysql -q
systemctl disable mariadb -q systemctl disable mariadb -q
@ -27,62 +61,8 @@ do_post_regen() {
systemctl is-active mariadb -q || systemctl start mariadb systemctl is-active mariadb -q || systemctl start mariadb
fi fi
if [ ! -f /etc/yunohost/mysql ]; then
# ensure that mysql is running
systemctl -q is-active mysql.service \
|| service mysql start
# generate and set new root password
mysql_password=$(ynh_string_random 10)
mysqladmin -s -u root -pyunohost password "$mysql_password" || {
if [ $FORCE -eq 1 ]; then
echo "It seems that you have already configured MySQL." \
"YunoHost needs to have a root access to MySQL to runs its" \
"applications, and is going to reset the MySQL root password." \
"You can find this new password in /etc/yunohost/mysql." >&2
# set new password with debconf
debconf-set-selections << EOF
$MYSQL_PKG mysql-server/root_password password $mysql_password
$MYSQL_PKG mysql-server/root_password_again password $mysql_password
EOF
# reconfigure Debian package
dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1
else
echo "It seems that you have already configured MySQL." \
"YunoHost needs to have a root access to MySQL to runs its" \
"applications, but the MySQL root password is unknown." \
"You must either pass --force to reset the password or" \
"put the current one into the file /etc/yunohost/mysql." >&2
exit 1
fi
}
# store new root password
echo "$mysql_password" | tee /etc/yunohost/mysql
chmod 400 /etc/yunohost/mysql
fi
[[ -z "$regen_conf_files" ]] \ [[ -z "$regen_conf_files" ]] \
|| service mysql restart || systemctl restart mysql
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -10,20 +10,4 @@ do_post_regen() {
chown -R redis:adm /var/log/redis chown -R redis:adm /var/log/redis
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -1,37 +0,0 @@
#!/bin/bash
set -e
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/templates/avahi-daemon
install -D -m 644 avahi-daemon.conf \
"${pending_dir}/etc/avahi/avahi-daemon.conf"
}
do_post_regen() {
regen_conf_files=$1
[[ -z "$regen_conf_files" ]] \
|| service avahi-daemon restart
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

54
data/hooks/conf_regen/37-mdns Executable file
View file

@ -0,0 +1,54 @@
#!/bin/bash
set -e
_generate_config() {
echo "domains:"
echo " - yunohost.local"
for domain in $YNH_DOMAINS; do
# Only keep .local domains (don't keep
[[ "$domain" =~ [^.]+\.[^.]+\.local$ ]] && echo "Subdomain $domain cannot be handled by Bonjour/Zeroconf/mDNS" >&2
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
echo " - $domain"
done
}
do_init_regen() {
do_pre_regen
do_post_regen /etc/systemd/system/yunomdns.service
systemctl enable yunomdns
}
do_pre_regen() {
pending_dir="$1"
cd /usr/share/yunohost/templates/mdns
mkdir -p ${pending_dir}/etc/systemd/system/
cp yunomdns.service ${pending_dir}/etc/systemd/system/
getent passwd mdns &>/dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group mdns
mkdir -p ${pending_dir}/etc/yunohost
_generate_config >${pending_dir}/etc/yunohost/mdns.yml
}
do_post_regen() {
regen_conf_files="$1"
chown mdns:mdns /etc/yunohost/mdns.yml
# If we changed the systemd ynh-override conf
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/yunomdns.service$"; then
systemctl daemon-reload
fi
# 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
systemctl enable yunomdns
fi
[[ -z "$regen_conf_files" ]] \
|| systemctl restart yunomdns
}
do_$1_regen ${@:2}

View file

@ -19,7 +19,7 @@ do_pre_regen() {
cp plain/dnsmasq.conf ${pending_dir}/etc/dnsmasq.conf cp plain/dnsmasq.conf ${pending_dir}/etc/dnsmasq.conf
# add resolver file # add resolver file
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 -s -4 https://ip.yunohost.org 2>/dev/null || true) ipv4=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
@ -32,6 +32,7 @@ do_pre_regen() {
# add domain conf files # add domain conf files
for domain in $YNH_DOMAINS; do for domain in $YNH_DOMAINS; do
[[ ! $domain =~ \.local$ ]] || continue
export domain export domain
ynh_render_template "domain.tpl" "${dnsmasq_dir}/${domain}" ynh_render_template "domain.tpl" "${dnsmasq_dir}/${domain}"
done done
@ -40,8 +41,10 @@ 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
[[ $YNH_DOMAINS =~ $domain ]] \ if [[ ! $YNH_DOMAINS =~ $domain ]] && [[ ! $domain =~ \.local$ ]]
|| touch "${dnsmasq_dir}/${domain}" then
touch "${dnsmasq_dir}/${domain}"
fi
done done
} }
@ -50,16 +53,14 @@ do_post_regen() {
# 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
if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf; then
then if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null; then
if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null
then
sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient
fi fi
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 name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >> /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
@ -71,8 +72,7 @@ do_post_regen() {
[[ -n "$regen_conf_files" ]] || return [[ -n "$regen_conf_files" ]] || return
# Remove / disable services likely to conflict with dnsmasq # Remove / disable services likely to conflict with dnsmasq
for SERVICE in systemd-resolved bind9 for SERVICE in systemd-resolved bind9; do
do
systemctl is-enabled $SERVICE &>/dev/null && systemctl disable $SERVICE 2>/dev/null systemctl is-enabled $SERVICE &>/dev/null && systemctl disable $SERVICE 2>/dev/null
systemctl is-active $SERVICE &>/dev/null && systemctl stop $SERVICE systemctl is-active $SERVICE &>/dev/null && systemctl stop $SERVICE
done done
@ -80,20 +80,4 @@ do_post_regen() {
systemctl restart dnsmasq systemctl restart dnsmasq
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -22,23 +22,4 @@ do_post_regen() {
|| systemctl restart unscd || systemctl restart unscd
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -2,6 +2,8 @@
set -e set -e
. /usr/share/yunohost/helpers
do_pre_regen() { do_pre_regen() {
pending_dir=$1 pending_dir=$1
@ -13,30 +15,16 @@ do_pre_regen() {
cp yunohost.conf "${fail2ban_dir}/filter.d/yunohost.conf" cp yunohost.conf "${fail2ban_dir}/filter.d/yunohost.conf"
cp jail.conf "${fail2ban_dir}/jail.conf" cp jail.conf "${fail2ban_dir}/jail.conf"
cp yunohost-jails.conf "${fail2ban_dir}/jail.d/"
export ssh_port="$(yunohost settings get 'security.ssh.port')"
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
[[ -z "$regen_conf_files" ]] \ [[ -z "$regen_conf_files" ]] \
|| service fail2ban restart || systemctl reload fail2ban
} }
FORCE=${2:-0} do_$1_regen ${@:2}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -133,6 +133,13 @@ class BaseSystemDiagnoser(Diagnoser):
summary="diagnosis_backports_in_sources_list", summary="diagnosis_backports_in_sources_list",
) )
if self.number_of_recent_auth_failure() > 500:
yield dict(
meta={"test": "high_number_auth_failure"},
status="WARNING",
summary="diagnosis_high_number_auth_failures",
)
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"]
@ -154,6 +161,23 @@ class BaseSystemDiagnoser(Diagnoser):
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):
# Those syslog facilities correspond to auth and authpriv
# c.f. https://unix.stackexchange.com/a/401398
# and https://wiki.archlinux.org/title/Systemd/Journal#Facility
cmd = "journalctl -q SYSLOG_FACILITY=10 SYSLOG_FACILITY=4 --since '1day ago' | grep 'authentication failure' | wc -l"
n_failures = check_output(cmd)
try:
return int(n_failures)
except Exception:
self.logger_warning(
"Failed to parse number of recent auth failures, expected an int, got '%s'"
% n_failures
)
return -1
def is_vulnerable_to_meltdown(self): def is_vulnerable_to_meltdown(self):
# meltdown CVE: https://security-tracker.debian.org/tracker/CVE-2017-5754 # meltdown CVE: https://security-tracker.debian.org/tracker/CVE-2017-5754

View file

@ -8,11 +8,15 @@ from publicsuffix import PublicSuffixList
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
from yunohost.utils.network import dig from yunohost.utils.dns import (
dig,
YNH_DYNDNS_DOMAINS,
is_yunohost_dyndns_domain,
is_special_use_tld,
)
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain from yunohost.domain import domain_list, _get_maindomain
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
class DNSRecordsDiagnoser(Diagnoser): class DNSRecordsDiagnoser(Diagnoser):
@ -25,19 +29,20 @@ class DNSRecordsDiagnoser(Diagnoser):
main_domain = _get_maindomain() main_domain = _get_maindomain()
all_domains = domain_list()["domains"] major_domains = domain_list(exclude_subdomains=True)["domains"]
for domain in all_domains: for domain in major_domains:
self.logger_debug("Diagnosing DNS conf for %s" % domain) self.logger_debug("Diagnosing DNS conf for %s" % domain)
is_subdomain = domain.split(".", 1)[1] in all_domains
for report in self.check_domain( for report in self.check_domain(
domain, domain == main_domain, is_subdomain=is_subdomain domain,
domain == main_domain,
): ):
yield report yield report
# Check if a domain buy by the user will expire soon # Check if a domain buy by the user will expire soon
psl = PublicSuffixList() psl = PublicSuffixList()
domains_from_registrar = [ domains_from_registrar = [
psl.get_public_suffix(domain) for domain in all_domains psl.get_public_suffix(domain) for domain in major_domains
] ]
domains_from_registrar = [ domains_from_registrar = [
domain for domain in domains_from_registrar if "." in domain domain for domain in domains_from_registrar if "." in domain
@ -48,16 +53,25 @@ class DNSRecordsDiagnoser(Diagnoser):
for report in self.check_expiration_date(domains_from_registrar): for report in self.check_expiration_date(domains_from_registrar):
yield report yield report
def check_domain(self, domain, is_main_domain, is_subdomain): def check_domain(self, domain, is_main_domain):
if is_special_use_tld(domain):
categories = []
yield dict(
meta={"domain": domain},
data={},
status="INFO",
summary="diagnosis_dns_specialusedomain",
)
base_dns_zone = _get_dns_zone_for_domain(domain)
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
) )
categories = ["basic", "mail", "xmpp", "extra"] categories = ["basic", "mail", "xmpp", "extra"]
# For subdomains, we only diagnosis A and AAAA records
if is_subdomain:
categories = ["basic"]
for category in categories: for category in categories:
@ -66,8 +80,21 @@ class DNSRecordsDiagnoser(Diagnoser):
results = {} results = {}
for r in records: for r in records:
id_ = r["type"] + ":" + r["name"] id_ = r["type"] + ":" + r["name"]
r["current"] = self.get_current_record(domain, r["name"], r["type"]) fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
# Ugly hack to not check mail records for subdomains stuff,
# otherwise will end up in a shitstorm of errors for people with many subdomains...
# Should find a cleaner solution in the suggested conf...
if r["type"] in ["MX", "TXT"] and fqdn not in [
domain,
f"mail._domainkey.{domain}",
f"_dmarc.{domain}",
]:
continue
r["current"] = self.get_current_record(fqdn, r["type"])
if r["value"] == "@": if r["value"] == "@":
r["value"] = domain + "." r["value"] = domain + "."
@ -90,7 +117,10 @@ class DNSRecordsDiagnoser(Diagnoser):
# A bad or missing A record is critical ... # A bad or missing A record is critical ...
# And so is a wrong AAAA record # And so is a wrong AAAA record
# (However, a missing AAAA record is acceptable) # (However, a missing AAAA record is acceptable)
if results["A:@"] != "OK" or results["AAAA:@"] == "WRONG": if (
results[f"A:{basename}"] != "OK"
or results[f"AAAA:{basename}"] == "WRONG"
):
return True return True
return False return False
@ -102,6 +132,12 @@ class DNSRecordsDiagnoser(Diagnoser):
status = "SUCCESS" status = "SUCCESS"
summary = "diagnosis_dns_good_conf" summary = "diagnosis_dns_good_conf"
# If status is okay and there's actually no expected records
# (e.g. XMPP disabled)
# then let's not yield any diagnosis line
if not records and "status" == "SUCCESS":
continue
output = dict( output = dict(
meta={"domain": domain, "category": category}, meta={"domain": domain, "category": category},
data=results, data=results,
@ -111,10 +147,7 @@ class DNSRecordsDiagnoser(Diagnoser):
if discrepancies: if discrepancies:
# For ynh-managed domains (nohost.me etc...), tell people to try to "yunohost dyndns update --force" # For ynh-managed domains (nohost.me etc...), tell people to try to "yunohost dyndns update --force"
if any( if is_yunohost_dyndns_domain(domain):
domain.endswith(ynh_dyndns_domain)
for ynh_dyndns_domain in YNH_DYNDNS_DOMAINS
):
output["details"] = ["diagnosis_dns_try_dyndns_update_force"] output["details"] = ["diagnosis_dns_try_dyndns_update_force"]
# Otherwise point to the documentation # Otherwise point to the documentation
else: else:
@ -123,10 +156,9 @@ class DNSRecordsDiagnoser(Diagnoser):
yield output yield output
def get_current_record(self, domain, name, type_): def get_current_record(self, fqdn, type_):
query = "%s.%s" % (name, domain) if name != "@" else domain success, answers = dig(fqdn, type_, resolvers="force_external")
success, answers = dig(query, type_, resolvers="force_external")
if success != "ok": if success != "ok":
return None return None
@ -154,7 +186,7 @@ class DNSRecordsDiagnoser(Diagnoser):
) )
# For SPF, ignore parts starting by ip4: or ip6: # For SPF, ignore parts starting by ip4: or ip6:
if r["name"] == "@": if "v=spf1" in r["value"]:
current = { current = {
part part
for part in current for part in current
@ -173,7 +205,6 @@ class DNSRecordsDiagnoser(Diagnoser):
""" """
Alert if expiration date of a domain is soon Alert if expiration date of a domain is soon
""" """
details = {"not_found": [], "error": [], "warning": [], "success": []} details = {"not_found": [], "error": [], "warning": [], "success": []}
for domain in domains: for domain in domains:
@ -183,6 +214,7 @@ class DNSRecordsDiagnoser(Diagnoser):
status_ns, _ = dig(domain, "NS", resolvers="force_external") status_ns, _ = dig(domain, "NS", resolvers="force_external")
status_a, _ = dig(domain, "A", resolvers="force_external") status_a, _ = dig(domain, "A", resolvers="force_external")
if "ok" not in [status_ns, status_a]: if "ok" not in [status_ns, status_a]:
# i18n: diagnosis_domain_not_found_details
details["not_found"].append( details["not_found"].append(
( (
"diagnosis_domain_%s_details" % (expire_date), "diagnosis_domain_%s_details" % (expire_date),
@ -217,6 +249,12 @@ class DNSRecordsDiagnoser(Diagnoser):
# Allow to ignore specifically a single domain # Allow to ignore specifically a single domain
if len(details[alert_type]) == 1: if len(details[alert_type]) == 1:
meta["domain"] = details[alert_type][0][1]["domain"] meta["domain"] = details[alert_type][0][1]["domain"]
# i18n: diagnosis_domain_expiration_not_found
# i18n: diagnosis_domain_expiration_error
# i18n: diagnosis_domain_expiration_warning
# i18n: diagnosis_domain_expiration_success
# i18n: diagnosis_domain_expiration_not_found_details
yield dict( yield dict(
meta=meta, meta=meta,
data={}, data={},

View file

@ -43,7 +43,7 @@ class PortsDiagnoser(Diagnoser):
for ipversion in ipversions: for ipversion in ipversions:
try: try:
r = Diagnoser.remote_diagnosis( r = Diagnoser.remote_diagnosis(
"check-ports", data={"ports": ports.keys()}, ipversion=ipversion "check-ports", data={"ports": list(ports)}, ipversion=ipversion
) )
results[ipversion] = r["ports"] results[ipversion] = r["ports"]
except Exception as e: except Exception as e:

View file

@ -8,6 +8,7 @@ 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
DIAGNOSIS_SERVER = "diagnosis.yunohost.org" DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
@ -34,6 +35,12 @@ class WebDiagnoser(Diagnoser):
summary="diagnosis_http_nginx_conf_not_up_to_date", summary="diagnosis_http_nginx_conf_not_up_to_date",
details=["diagnosis_http_nginx_conf_not_up_to_date_details"], details=["diagnosis_http_nginx_conf_not_up_to_date_details"],
) )
elif is_special_use_tld(domain):
yield dict(
meta={"domain": domain},
status="INFO",
summary="diagnosis_http_special_use_tld",
)
else: else:
domains_to_check.append(domain) domains_to_check.append(domain)
@ -115,6 +122,10 @@ class WebDiagnoser(Diagnoser):
for domain in domains: for domain in domains:
# i18n: diagnosis_http_bad_status_code
# i18n: diagnosis_http_connection_error
# i18n: diagnosis_http_timeout
# If both IPv4 and IPv6 (if applicable) are good # If both IPv4 and IPv6 (if applicable) are good
if all( if all(
results[ipversion][domain]["status"] == "ok" for ipversion in ipversions results[ipversion][domain]["status"] == "ok" for ipversion in ipversions

View file

@ -12,7 +12,7 @@ from moulinette.utils.filesystem import read_yaml
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
from yunohost.domain import _get_maindomain, domain_list from yunohost.domain import _get_maindomain, domain_list
from yunohost.settings import settings_get from yunohost.settings import settings_get
from yunohost.utils.network import dig from yunohost.utils.dns import dig
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml"
@ -35,11 +35,11 @@ class MailDiagnoser(Diagnoser):
# TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) # TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent)
# TODO check for unusual failed sending attempt being refused in the logs ? # TODO check for unusual failed sending attempt being refused in the logs ?
checks = [ checks = [
"check_outgoing_port_25", "check_outgoing_port_25", # i18n: diagnosis_mail_outgoing_port_25_ok
"check_ehlo", "check_ehlo", # i18n: diagnosis_mail_ehlo_ok
"check_fcrdns", "check_fcrdns", # i18n: diagnosis_mail_fcrdns_ok
"check_blacklist", "check_blacklist", # i18n: diagnosis_mail_blacklist_ok
"check_queue", "check_queue", # i18n: diagnosis_mail_queue_ok
] ]
for check in checks: for check in checks:
self.logger_debug("Running " + check) self.logger_debug("Running " + check)
@ -102,6 +102,10 @@ class MailDiagnoser(Diagnoser):
continue continue
if r["status"] != "ok": if r["status"] != "ok":
# i18n: diagnosis_mail_ehlo_bad_answer
# i18n: diagnosis_mail_ehlo_bad_answer_details
# i18n: diagnosis_mail_ehlo_unreachable
# i18n: diagnosis_mail_ehlo_unreachable_details
summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_") summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_")
yield dict( yield dict(
meta={"test": "mail_ehlo", "ipversion": ipversion}, meta={"test": "mail_ehlo", "ipversion": ipversion},

View file

@ -77,7 +77,9 @@ class SystemResourcesDiagnoser(Diagnoser):
# Ignore /dev/loop stuff which are ~virtual partitions ? (e.g. mounted to /snap/) # Ignore /dev/loop stuff which are ~virtual partitions ? (e.g. mounted to /snap/)
disk_partitions = [ disk_partitions = [
d for d in disk_partitions if not d.device.startswith("/dev/loop") d
for d in disk_partitions
if d.mountpoint in ["/", "/var"] or not d.device.startswith("/dev/loop")
] ]
for disk_partition in disk_partitions: for disk_partition in disk_partitions:
@ -139,7 +141,7 @@ class SystemResourcesDiagnoser(Diagnoser):
status="ERROR", status="ERROR",
summary="diagnosis_rootfstotalspace_critical", summary="diagnosis_rootfstotalspace_critical",
) )
if main_space < 14 * GB: elif main_space < 14 * GB:
yield dict( yield dict(
meta={"test": "rootfstotalspace"}, meta={"test": "rootfstotalspace"},
data={"space": human_size(main_space)}, data={"space": human_size(main_space)},

View file

@ -1,9 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
import os import os
import re
from yunohost.settings import settings_get
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
from yunohost.regenconf import _get_regenconf_infos, _calculate_hash from yunohost.regenconf import _get_regenconf_infos, _calculate_hash
from moulinette.utils.filesystem import read_file
class RegenconfDiagnoser(Diagnoser): class RegenconfDiagnoser(Diagnoser):
@ -35,6 +38,32 @@ class RegenconfDiagnoser(Diagnoser):
details=["diagnosis_regenconf_manually_modified_details"], details=["diagnosis_regenconf_manually_modified_details"],
) )
if (
any(f["path"] == "/etc/ssh/sshd_config" for f in regenconf_modified_files)
and os.system(
"grep -q '^ *AllowGroups\\|^ *AllowUsers' /etc/ssh/sshd_config"
)
!= 0
):
yield dict(
meta={"test": "sshd_config_insecure"},
status="ERROR",
summary="diagnosis_sshd_config_insecure",
)
# Check consistency between actual ssh port in sshd_config vs. setting
ssh_port_setting = settings_get("security.ssh.port")
ssh_port_line = re.findall(
r"\bPort *([0-9]{2,5})\b", read_file("/etc/ssh/sshd_config")
)
if len(ssh_port_line) == 1 and int(ssh_port_line[0]) != ssh_port_setting:
yield dict(
meta={"test": "sshd_config_port_inconsistency"},
status="WARNING",
summary="diagnosis_sshd_config_inconsistent",
details=["diagnosis_sshd_config_inconsistent_details"],
)
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():

View file

@ -0,0 +1,96 @@
#!/usr/bin/env python
import os
from yunohost.app import app_list
from yunohost.diagnosis import Diagnoser
class AppDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies = []
def run(self):
apps = app_list(full=True)["apps"]
for app in apps:
app["issues"] = list(self.issues(app))
if not any(app["issues"] for app in apps):
yield dict(
meta={"test": "apps"},
status="SUCCESS",
summary="diagnosis_apps_allgood",
)
else:
for app in apps:
if not app["issues"]:
continue
level = (
"ERROR"
if any(issue[0] == "error" for issue in app["issues"])
else "WARNING"
)
yield dict(
meta={"test": "apps", "app": app["name"]},
status=level,
summary="diagnosis_apps_issue",
details=[issue[1] for issue in app["issues"]],
)
def issues(self, app):
# Check quality level in catalog
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":
yield ("error", "diagnosis_apps_not_in_app_catalog")
elif (
not isinstance(app["from_catalog"].get("level"), int)
or app["from_catalog"]["level"] == 0
):
yield ("error", "diagnosis_apps_broken")
elif app["from_catalog"]["level"] <= 4:
yield ("warning", "diagnosis_apps_bad_quality")
# Check for super old, deprecated practices
yunohost_version_req = (
app["manifest"].get("requirements", {}).get("yunohost", "").strip(">= ")
)
if yunohost_version_req.startswith("2."):
yield ("error", "diagnosis_apps_outdated_ynh_requirement")
deprecated_helpers = [
"yunohost app setting",
"yunohost app checkurl",
"yunohost app checkport",
"yunohost app initdb",
"yunohost tools port-available",
]
for deprecated_helper in deprecated_helpers:
if (
os.system(
f"grep -hr '{deprecated_helper}' {app['setting_path']}/scripts/ | grep -v -q '^\\s*#'"
)
== 0
):
yield ("error", "diagnosis_apps_deprecated_practices")
old_arg_regex = r"^domain=\${?[0-9]"
if (
os.system(
f"grep -q '{old_arg_regex}' {app['setting_path']}/scripts/install"
)
== 0
):
yield ("error", "diagnosis_apps_deprecated_practices")
def main(args, env, loggers):
return AppDiagnoser(args, env, loggers).diagnose()

View file

@ -0,0 +1,32 @@
#!/bin/bash
user=$1
readonly MEDIA_GROUP=multimedia
readonly MEDIA_DIRECTORY=/home/yunohost.multimedia
# We only do this if multimedia directory is enabled (= the folder exists)
[ -e "$MEDIA_DIRECTORY" ] || exit 0
mkdir -p "$MEDIA_DIRECTORY/$user"
mkdir -p "$MEDIA_DIRECTORY/$user/Music"
mkdir -p "$MEDIA_DIRECTORY/$user/Picture"
mkdir -p "$MEDIA_DIRECTORY/$user/Video"
mkdir -p "$MEDIA_DIRECTORY/$user/eBook"
ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share"
# Création du lien symbolique dans le home de l'utilisateur.
#link will only be created if the home directory of the user exists and if it's located in '/home' folder
user_home="$(getent passwd $user | cut -d: -f6 | grep '^/home/')"
if [[ -d "$user_home" ]]; then
ln -sfn "$MEDIA_DIRECTORY/$user" "$user_home/Multimedia"
fi
# Propriétaires des dossiers utilisateurs.
chown -R $user "$MEDIA_DIRECTORY/$user"
## Application des droits étendus sur le dossier multimedia.
# Droit d'écriture pour le groupe et le groupe multimedia en acl et droit de lecture pour other:
setfacl -RnL -m g:$MEDIA_GROUP:rwX,g::rwX,o:r-X "$MEDIA_DIRECTORY/$user"
# 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/$user"
# 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/$user"

View file

@ -0,0 +1,8 @@
#!/bin/bash
user=$1
MEDIA_DIRECTORY=/home/yunohost.multimedia
if [ -n "$user" ] && [ -e "$MEDIA_DIRECTORY/$user" ]; then
sudo rm -r "$MEDIA_DIRECTORY/$user"
fi

View file

@ -1,61 +1,53 @@
#!/bin/bash
backup_dir="${1}/conf/ldap" backup_dir="${1}/conf/ldap"
if [[ $EUID -ne 0 ]]; then systemctl stop slapd
# We need to execute this script as root, since the ldap # Create a directory for backup
# service will be shut down during the operation (and sudo TMPDIR="/tmp/$(date +%s)"
# won't be available) mkdir -p "$TMPDIR"
/bin/bash $(readlink -f $0) $1
else die() {
service slapd stop || true
# Create a directory for backup
TMPDIR="/tmp/$(date +%s)"
mkdir -p "$TMPDIR"
die() {
state=$1 state=$1
error=$2 error=$2
# Restore saved configuration and database # Restore saved configuration and database
[[ $state -ge 1 ]] \ [[ $state -ge 1 ]] \
&& (rm -rf /etc/ldap/slapd.d && && (rm -rf /etc/ldap/slapd.d \
mv "${TMPDIR}/slapd.d" /etc/ldap/slapd.d) && mv "${TMPDIR}/slapd.d" /etc/ldap/slapd.d)
[[ $state -ge 2 ]] \ [[ $state -ge 2 ]] \
&& (rm -rf /var/lib/ldap && && (rm -rf /var/lib/ldap \
mv "${TMPDIR}/ldap" /var/lib/ldap) && mv "${TMPDIR}/ldap" /var/lib/ldap)
chown -R openldap: /etc/ldap/slapd.d /var/lib/ldap chown -R openldap: /etc/ldap/slapd.d /var/lib/ldap
service slapd start systemctl start slapd
rm -rf "$TMPDIR" rm -rf "$TMPDIR"
# Print an error message and exit # Print an error message and exit
printf "%s" "$error" 1>&2 printf "%s" "$error" 1>&2
exit 1 exit 1
} }
# Restore the configuration # Restore the configuration
mv /etc/ldap/slapd.d "$TMPDIR" mv /etc/ldap/slapd.d "$TMPDIR"
mkdir -p /etc/ldap/slapd.d mkdir -p /etc/ldap/slapd.d
cp -a "${backup_dir}/ldap.conf" /etc/ldap/ldap.conf cp -a "${backup_dir}/ldap.conf" /etc/ldap/ldap.conf
cp -a "${backup_dir}/slapd.ldif" /etc/ldap/slapd.ldif # Legacy thing but we need it to force the regen-conf in case of it exist
# Legacy thing but we need it to force the regen-conf in case of it exist [ ! -e "${backup_dir}/slapd.conf" ] \
cp -a "${backup_dir}/slapd.conf" /etc/ldap/slapd.conf || cp -a "${backup_dir}/slapd.conf" /etc/ldap/slapd.conf
slapadd -F /etc/ldap/slapd.d -b cn=config \ slapadd -F /etc/ldap/slapd.d -b cn=config \
-l "${backup_dir}/cn=config.master.ldif" \ -l "${backup_dir}/cn=config.master.ldif" \
|| die 1 "Unable to restore LDAP configuration" || die 1 "Unable to restore LDAP configuration"
chown -R openldap: /etc/ldap/slapd.d chown -R openldap: /etc/ldap/slapd.d
# Restore the database # Restore the database
mv /var/lib/ldap "$TMPDIR" mv /var/lib/ldap "$TMPDIR"
mkdir -p /var/lib/ldap mkdir -p /var/lib/ldap
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org \ slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org \
-l "${backup_dir}/dc=yunohost-dc=org.ldif" \ -l "${backup_dir}/dc=yunohost-dc=org.ldif" \
|| die 2 "Unable to restore LDAP database" || die 2 "Unable to restore LDAP database"
chown -R openldap: /var/lib/ldap chown -R openldap: /var/lib/ldap
service slapd start systemctl start slapd
rm -rf "$TMPDIR" rm -rf "$TMPDIR"
fi

View file

@ -1,9 +0,0 @@
backup_dir="$1/conf/ssh"
if [ -d /etc/ssh/ ]; then
cp -a $backup_dir/. /etc/ssh
service ssh restart
else
echo "SSH is not installed"
fi

View file

@ -1,5 +0,0 @@
# We don't backup/restore mysql password anymore
# c.f. https://github.com/YunoHost/yunohost/pull/912
# This is a dummy empty file as a workaround for
# https://github.com/YunoHost/issues/issues/1553 until it is fixed

View file

@ -1,3 +0,0 @@
backup_dir="$1/conf/ssowat"
cp -a $backup_dir/. /etc/ssowat

View file

@ -6,8 +6,4 @@ set -eu
# Source YNH helpers # Source YNH helpers
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
# Backup destination ynh_restore_file --origin_path="/home/yunohost.multimedia" --not_mandatory
backup_dir="${1}/conf/ssowat"
# Backup the configuration
ynh_backup "/etc/ssowat" "$backup_dir"

View file

@ -1,4 +0,0 @@
backup_dir="$1/conf/ynh/firewall"
cp -a $backup_dir/. /etc/yunohost
yunohost firewall reload

View file

@ -0,0 +1,8 @@
backup_dir="$1/conf/ynh"
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host
cp -a "${backup_dir}/firewall.yml" /etc/yunohost/firewall.yml
cp -a "${backup_dir}/domains" /etc/yunohost/domains
[ ! -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}/dkim" ] || cp -raT "${backup_dir}/dkim" "/etc/dkim"

View file

@ -3,5 +3,3 @@ backup_dir="$1/conf/ynh/certs"
mkdir -p /etc/yunohost/certs/ mkdir -p /etc/yunohost/certs/
cp -a $backup_dir/. /etc/yunohost/certs/ cp -a $backup_dir/. /etc/yunohost/certs/
service nginx reload
service metronome reload

View file

@ -1,9 +0,0 @@
#!/bin/bash
backup_dir="$1/conf/dkim"
cp -a $backup_dir/etc/dkim/. /etc/dkim
chown -R root:root /etc/dkim
chown _rspamd:root /etc/dkim
chown _rspamd:root /etc/dkim/*.mail.key

View file

@ -2,7 +2,3 @@ backup_dir="$1/data/mail"
cp -a $backup_dir/. /var/mail/ || echo 'No mail found' cp -a $backup_dir/. /var/mail/ || echo 'No mail found'
chown -R vmail:mail /var/mail/ chown -R vmail:mail /var/mail/
# Restart services to use migrated certs
service postfix restart
service dovecot restart

View file

@ -1,7 +0,0 @@
backup_dir="$1/conf/xmpp"
cp -a $backup_dir/etc/. /etc/metronome
cp -a $backup_dir/var/. /var/lib/metronome
# Restart to apply new conf and certs
service metronome restart

View file

@ -0,0 +1,4 @@
backup_dir="$1/data/xmpp"
cp -a $backup_dir/var_lib_metronome/. /var/lib/metronome
cp -a $backup_dir/var_xmpp-upload/. /var/xmpp-upload

View file

@ -1,7 +0,0 @@
backup_dir="$1/conf/nginx"
# Copy all conf except apps specific conf located in DOMAIN.d
find $backup_dir/ -mindepth 1 -maxdepth 1 -name '*.d' -or -exec cp -a {} /etc/nginx/conf.d/ \;
# Restart to use new conf and certs
service nginx restart

View file

@ -1,6 +0,0 @@
backup_dir="$1/conf/cron"
cp -a $backup_dir/. /etc/cron.d
# Restart just in case
service cron restart

View file

@ -1,3 +0,0 @@
backup_dir="$1/conf/ynh"
cp -a "${backup_dir}/current_host" /etc/yunohost/current_host

View file

@ -1,10 +0,0 @@
#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/ynh/dyndns"
cd "$YNH_CWD"
# Restore file if exists
ynh_restore_file --origin_path="/etc/yunohost/dyndns" --not_mandatory
ynh_restore_file --origin_path="/etc/cron.d/yunohost-dyndns" --not_mandatory

View file

@ -0,0 +1,12 @@
#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/manually_modified_files"
cd "$YNH_CWD"
for file in $(cat ./manually_modified_files_list); do
ynh_restore_file --origin_path="$file" --not_mandatory
done
ynh_restore_file --origin_path="/etc/ssowat/conf.json.persistent" --not_mandatory

View file

@ -0,0 +1,55 @@
version = "1.0"
i18n = "domain_config"
#
# Other things we may want to implement in the future:
#
# - maindomain handling
# - default app
# - autoredirect www in nginx conf
# - ?
#
[feature]
[feature.mail]
#services = ['postfix', 'dovecot']
[feature.mail.features_disclaimer]
type = "alert"
style = "warning"
icon = "warning"
[feature.mail.mail_out]
type = "boolean"
default = 1
[feature.mail.mail_in]
type = "boolean"
default = 1
#[feature.mail.backup_mx]
#type = "tags"
#default = []
#pattern.regexp = '^([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$'
#pattern.error = "pattern_error"
[feature.xmpp]
[feature.xmpp.xmpp]
type = "boolean"
default = 0
[dns]
[dns.registrar]
optional = true
# This part is automatically generated in DomainConfigPanel
# [dns.advanced]
#
# [dns.advanced.ttl]
# type = "number"
# min = 0
# default = 3600

View file

@ -151,12 +151,6 @@
ipv4: true ipv4: true
ipv6: false ipv6: false
domain: false domain: false
- name: Invaluement
dns_server: sip.invaluement.com
website: https://www.invaluement.com/
ipv4: true
ipv6: false
domain: false
# Added cause it supports IPv6 # Added cause it supports IPv6
- name: AntiCaptcha.NET IPv6 - name: AntiCaptcha.NET IPv6
dns_server: dnsbl6.anticaptcha.net dns_server: dnsbl6.anticaptcha.net
@ -164,12 +158,6 @@
ipv4: false ipv4: false
ipv6: true ipv6: true
domain: false domain: false
- name: SPFBL.net RBL
dns_server: dnsbl.spfbl.net
website: https://spfbl.net/en/dnsbl/
ipv4: true
ipv6: true
domain: true
- name: Suomispam Blacklist - name: Suomispam Blacklist
dns_server: bl.suomispam.net dns_server: bl.suomispam.net
website: http://suomispam.net/ website: http://suomispam.net/

View file

@ -1,91 +0,0 @@
parents:
ou=users:
ou: users
objectClass:
- organizationalUnit
- top
ou=domains:
ou: domains
objectClass:
- organizationalUnit
- top
ou=apps:
ou: apps
objectClass:
- organizationalUnit
- top
ou=permission:
ou: permission
objectClass:
- organizationalUnit
- top
ou=groups:
ou: groups
objectClass:
- organizationalUnit
- top
ou=sudo:
ou: sudo
objectClass:
- organizationalUnit
- top
children:
cn=admin,ou=sudo:
cn: admin
sudoUser: admin
sudoHost: ALL
sudoCommand: ALL
sudoOption: "!authenticate"
objectClass:
- sudoRole
- top
cn=admins,ou=groups:
cn: admins
gidNumber: "4001"
memberUid: admin
objectClass:
- posixGroup
- top
cn=all_users,ou=groups:
cn: all_users
gidNumber: "4002"
objectClass:
- posixGroup
- groupOfNamesYnh
cn=visitors,ou=groups:
cn: visitors
gidNumber: "4003"
objectClass:
- posixGroup
- groupOfNamesYnh
depends_children:
cn=mail.main,ou=permission:
cn: mail.main
gidNumber: "5001"
objectClass:
- posixGroup
- permissionYnh
groupPermission:
- "cn=all_users,ou=groups,dc=yunohost,dc=org"
authHeader: "FALSE"
label: "E-mail"
showTile: "FALSE"
isProtected: "TRUE"
cn=xmpp.main,ou=permission:
cn: xmpp.main
gidNumber: "5002"
objectClass:
- posixGroup
- permissionYnh
groupPermission:
- "cn=all_users,ou=groups,dc=yunohost,dc=org"
authHeader: "FALSE"
label: "XMPP"
showTile: "FALSE"
isProtected: "TRUE"

View file

@ -0,0 +1,649 @@
[aliyun]
[aliyun.auth_key_id]
type = "string"
redact = true
[aliyun.auth_secret]
type = "string"
redact = true
[aurora]
[aurora.auth_api_key]
type = "string"
redact = true
[aurora.auth_secret_key]
type = "string"
redact = true
[azure]
[azure.auth_client_id]
type = "string"
redact = true
[azure.auth_client_secret]
type = "string"
redact = true
[azure.auth_tenant_id]
type = "string"
redact = true
[azure.auth_subscription_id]
type = "string"
redact = true
[azure.resource_group]
type = "string"
redact = true
[cloudflare]
[cloudflare.auth_username]
type = "string"
redact = true
[cloudflare.auth_token]
type = "string"
redact = true
[cloudflare.zone_id]
type = "string"
redact = true
[cloudns]
[cloudns.auth_id]
type = "string"
redact = true
[cloudns.auth_subid]
type = "string"
redact = true
[cloudns.auth_subuser]
type = "string"
redact = true
[cloudns.auth_password]
type = "password"
[cloudns.weight]
type = "number"
[cloudns.port]
type = "number"
[cloudxns]
[cloudxns.auth_username]
type = "string"
redact = true
[cloudxns.auth_token]
type = "string"
redact = true
[conoha]
[conoha.auth_region]
type = "string"
redact = true
[conoha.auth_token]
type = "string"
redact = true
[conoha.auth_username]
type = "string"
redact = true
[conoha.auth_password]
type = "password"
[conoha.auth_tenant_id]
type = "string"
redact = true
[constellix]
[constellix.auth_username]
type = "string"
redact = true
[constellix.auth_token]
type = "string"
redact = true
[digitalocean]
[digitalocean.auth_token]
type = "string"
redact = true
[dinahosting]
[dinahosting.auth_username]
type = "string"
redact = true
[dinahosting.auth_password]
type = "password"
[directadmin]
[directadmin.auth_password]
type = "password"
[directadmin.auth_username]
type = "string"
redact = true
[directadmin.endpoint]
type = "string"
redact = true
[dnsimple]
[dnsimple.auth_token]
type = "string"
redact = true
[dnsimple.auth_username]
type = "string"
redact = true
[dnsimple.auth_password]
type = "password"
[dnsimple.auth_2fa]
type = "string"
redact = true
[dnsmadeeasy]
[dnsmadeeasy.auth_username]
type = "string"
redact = true
[dnsmadeeasy.auth_token]
type = "string"
redact = true
[dnspark]
[dnspark.auth_username]
type = "string"
redact = true
[dnspark.auth_token]
type = "string"
redact = true
[dnspod]
[dnspod.auth_username]
type = "string"
redact = true
[dnspod.auth_token]
type = "string"
redact = true
[dreamhost]
[dreamhost.auth_token]
type = "string"
redact = true
[dynu]
[dynu.auth_token]
type = "string"
redact = true
[easydns]
[easydns.auth_username]
type = "string"
redact = true
[easydns.auth_token]
type = "string"
redact = true
[easyname]
[easyname.auth_username]
type = "string"
redact = true
[easyname.auth_password]
type = "password"
[euserv]
[euserv.auth_username]
type = "string"
redact = true
[euserv.auth_password]
type = "password"
[exoscale]
[exoscale.auth_key]
type = "string"
redact = true
[exoscale.auth_secret]
type = "string"
redact = true
[gandi]
[gandi.auth_token]
type = "string"
redact = true
[gandi.api_protocol]
type = "string"
choices.rpc = "RPC"
choices.rest = "REST"
default = "rest"
visible = "false"
[gehirn]
[gehirn.auth_token]
type = "string"
redact = true
[gehirn.auth_secret]
type = "string"
redact = true
[glesys]
[glesys.auth_username]
type = "string"
redact = true
[glesys.auth_token]
type = "string"
redact = true
[godaddy]
[godaddy.auth_key]
type = "string"
redact = true
[godaddy.auth_secret]
type = "string"
redact = true
[googleclouddns]
[goggleclouddns.auth_service_account_info]
type = "string"
redact = true
[gransy]
[gransy.auth_username]
type = "string"
redact = true
[gransy.auth_password]
type = "password"
[gratisdns]
[gratisdns.auth_username]
type = "string"
redact = true
[gratisdns.auth_password]
type = "password"
[henet]
[henet.auth_username]
type = "string"
redact = true
[henet.auth_password]
type = "password"
[hetzner]
[hetzner.auth_token]
type = "string"
redact = true
[hostingde]
[hostingde.auth_token]
type = "string"
redact = true
[hover]
[hover.auth_username]
type = "string"
redact = true
[hover.auth_password]
type = "password"
[infoblox]
[infoblox.auth_user]
type = "string"
redact = true
[infoblox.auth_psw]
type = "password"
[infoblox.ib_view]
type = "string"
redact = true
[infoblox.ib_host]
type = "string"
redact = true
[infomaniak]
[infomaniak.auth_token]
type = "string"
redact = true
[internetbs]
[internetbs.auth_key]
type = "string"
redact = true
[internetbs.auth_password]
type = "string"
redact = true
[inwx]
[inwx.auth_username]
type = "string"
redact = true
[inwx.auth_password]
type = "password"
[joker]
[joker.auth_token]
type = "string"
redact = true
[linode]
[linode.auth_token]
type = "string"
redact = true
[linode4]
[linode4.auth_token]
type = "string"
redact = true
[localzone]
[localzone.filename]
type = "string"
redact = true
[luadns]
[luadns.auth_username]
type = "string"
redact = true
[luadns.auth_token]
type = "string"
redact = true
[memset]
[memset.auth_token]
type = "string"
redact = true
[mythicbeasts]
[mythicbeasts.auth_username]
type = "string"
redact = true
[mythicbeasts.auth_password]
type = "password"
[mythicbeasts.auth_token]
type = "string"
redact = true
[namecheap]
[namecheap.auth_token]
type = "string"
redact = true
[namecheap.auth_username]
type = "string"
redact = true
[namecheap.auth_client_ip]
type = "string"
redact = true
[namecheap.auth_sandbox]
type = "string"
redact = true
[namesilo]
[namesilo.auth_token]
type = "string"
redact = true
[netcup]
[netcup.auth_customer_id]
type = "string"
redact = true
[netcup.auth_api_key]
type = "string"
redact = true
[netcup.auth_api_password]
type = "string"
redact = true
[nfsn]
[nfsn.auth_username]
type = "string"
redact = true
[nfsn.auth_token]
type = "string"
redact = true
[njalla]
[njalla.auth_token]
type = "string"
redact = true
[nsone]
[nsone.auth_token]
type = "string"
redact = true
[onapp]
[onapp.auth_username]
type = "string"
redact = true
[onapp.auth_token]
type = "string"
redact = true
[onapp.auth_server]
type = "string"
redact = true
[online]
[online.auth_token]
type = "string"
redact = true
[ovh]
[ovh.auth_entrypoint]
type = "select"
choices = ["ovh-eu", "ovh-ca", "soyoustart-eu", "soyoustart-ca", "kimsufi-eu", "kimsufi-ca"]
default = "ovh-eu"
[ovh.auth_application_key]
type = "string"
redact = true
[ovh.auth_application_secret]
type = "string"
redact = true
[ovh.auth_consumer_key]
type = "string"
redact = true
[plesk]
[plesk.auth_username]
type = "string"
redact = true
[plesk.auth_password]
type = "password"
[plesk.plesk_server]
type = "string"
redact = true
[pointhq]
[pointhq.auth_username]
type = "string"
redact = true
[pointhq.auth_token]
type = "string"
redact = true
[powerdns]
[powerdns.auth_token]
type = "string"
redact = true
[powerdns.pdns_server]
type = "string"
redact = true
[powerdns.pdns_server_id]
type = "string"
redact = true
[powerdns.pdns_disable_notify]
type = "boolean"
[rackspace]
[rackspace.auth_account]
type = "string"
redact = true
[rackspace.auth_username]
type = "string"
redact = true
[rackspace.auth_api_key]
type = "string"
redact = true
[rackspace.auth_token]
type = "string"
redact = true
[rackspace.sleep_time]
type = "string"
redact = true
[rage4]
[rage4.auth_username]
type = "string"
redact = true
[rage4.auth_token]
type = "string"
redact = true
[rcodezero]
[rcodezero.auth_token]
type = "string"
redact = true
[route53]
[route53.auth_access_key]
type = "string"
redact = true
[route53.auth_access_secret]
type = "string"
redact = true
[route53.private_zone]
type = "string"
redact = true
[route53.auth_username]
type = "string"
redact = true
[route53.auth_token]
type = "string"
redact = true
[safedns]
[safedns.auth_token]
type = "string"
redact = true
[sakuracloud]
[sakuracloud.auth_token]
type = "string"
redact = true
[sakuracloud.auth_secret]
type = "string"
redact = true
[softlayer]
[softlayer.auth_username]
type = "string"
redact = true
[softlayer.auth_api_key]
type = "string"
redact = true
[transip]
[transip.auth_username]
type = "string"
redact = true
[transip.auth_api_key]
type = "string"
redact = true
[ultradns]
[ultradns.auth_token]
type = "string"
redact = true
[ultradns.auth_username]
type = "string"
redact = true
[ultradns.auth_password]
type = "password"
[vultr]
[vultr.auth_token]
type = "string"
redact = true
[yandex]
[yandex.auth_token]
type = "string"
redact = true
[zeit]
[zeit.auth_token]
type = "string"
redact = true
[zilore]
[zilore.auth_key]
type = "string"
redact = true
[zonomi]
[zonomy.auth_token]
type = "string"
redact = true
[zonomy.auth_entrypoint]
type = "string"
redact = true

View file

@ -1,68 +0,0 @@
# This file is part of avahi.
#
# avahi is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# avahi 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 General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with avahi; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
# See avahi-daemon.conf(5) for more information on this configuration
# file!
[server]
host-name=yunohost
domain-name=local
#browse-domains=0pointer.de, zeroconf.org
use-ipv4=yes
use-ipv6=yes
#allow-interfaces=eth0
#deny-interfaces=eth1
#check-response-ttl=no
#use-iff-running=no
#enable-dbus=yes
#disallow-other-stacks=no
#allow-point-to-point=no
#cache-entries-max=4096
#clients-max=4096
#objects-per-client-max=1024
#entries-per-entry-group-max=32
ratelimit-interval-usec=1000000
ratelimit-burst=1000
[wide-area]
enable-wide-area=yes
[publish]
#disable-publishing=no
#disable-user-service-publishing=no
#add-service-cookie=no
#publish-addresses=yes
#publish-hinfo=yes
#publish-workstation=yes
#publish-domain=yes
#publish-dns-servers=192.168.50.1, 192.168.50.2
#publish-resolv-conf-dns-servers=yes
#publish-aaaa-on-ipv4=yes
#publish-a-on-ipv6=no
[reflector]
#enable-reflector=no
#reflect-ipv=no
[rlimits]
#rlimit-as=
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=768
rlimit-stack=4194304
rlimit-nproc=3

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