Compare commits

..

425 commits

Author SHA1 Message Date
Alexandre Aubin
54fd311bec Update changelog for 12.0.2 2024-08-01 18:09:47 +02:00
Alexandre Aubin
7a45675f7a Merge remote-tracking branch 'origin/dev' into bookworm 2024-08-01 18:08:06 +02:00
Alexandre Aubin
0503a38a74 bullseye->bookworm: add a trick to flag the migration as done if it's still marked as pending 2024-07-31 00:06:33 +02:00
Alexandre Aubin
eb1d715764 Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-31 00:02:19 +02:00
Kayou
7b50c4eb6a
remove redis regen conf too 2024-07-30 15:38:58 +02:00
Alexandre Aubin
6f1e3411fc Update changelog for 12.0.1 2024-07-26 22:48:10 +02:00
Alexandre Aubin
a1e63a17bb Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-26 21:19:26 +02:00
Alexandre Aubin
ccfea312fe Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-26 21:00:17 +02:00
Alexandre Aubin
9a6ad19c0e apps/ssowat: fix default value for auth_header and protect_against_basic_auth_spoofing 2024-07-26 20:55:27 +02:00
Alexandre Aubin
d0ce8cce53 Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-25 19:29:59 +02:00
Alexandre Aubin
970e2e2dbc services: redis ain't installed by default anymore on yunohost 2024-07-25 18:53:26 +02:00
Alexandre Aubin
f547ac2515
Merge pull request #1919 from YunoHost/fix-appconfig-panel
appconfig panel: new values were replaced by default values
2024-07-23 17:31:35 +02:00
Kayou
a069cda08c
fix permission test 2024-07-23 12:17:16 +02:00
Kayou
03def5b109
appconfig panel: new values were replaced by default values 2024-07-23 11:58:35 +02:00
Alexandre Aubin
505e3db3bb ci: fallback to bookworm branch for build such that even on PR on top of bookworm the ci should work ... 2024-07-22 04:22:54 +02:00
Alexandre Aubin
42114978af
Update regenconf.py: cleanup legacy rspamd and metronome hash entries 2024-07-18 13:40:22 +02:00
Alexandre Aubin
88b11bee09 mail: fix opendkim assuming mails arent authenticated because of missing {auth_type} from postfix 2024-07-17 18:37:15 +02:00
Alexandre Aubin
b9178e750c Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-17 17:56:44 +02:00
Alexandre Aubin
609748e8c2 mail: Make sure to restart opendkim after regenconf 2024-07-17 17:45:32 +02:00
Alexandre Aubin
0ade9d0e6f Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-17 16:57:08 +02:00
Alexandre Aubin
6453d15011 bullseye->bookworm: fix the /var/log/yunohost/operations folder migration, in particular because the new folder will already exist when this code is triggered after the bullseye->bookworm (because 'yunohost tools regen-conf' will create a file in the new folder before actually ariving at this code) so we can't just rely on testing wether or not the new folder exists 2024-07-17 16:56:55 +02:00
9a0960dcf1 log.py: use os.path.join instead 2024-07-17 00:03:41 +02:00
91f747eaee log.py: fix listing of log files 2024-07-17 00:02:58 +02:00
03a5c3d144 Ensure postgresql is upgraded to 15.
Some apps required pg 16, so pg_upgradecluster tries to upgrade 13 to 16 and fails (cluster already exists)
2024-07-16 23:02:25 +02:00
Alexandre Aubin
443eac47ca Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-16 22:59:56 +02:00
Alexandre Aubin
946d2289d5 cleanup: we probably don't need to keep the super-legacy service entries anymore 2024-07-15 23:02:52 +02:00
Alexandre Aubin
daa4c39899 debian: remove dependency to redis-server 2024-07-15 22:30:17 +02:00
Alexandre Aubin
6638ee33b0 Remove trick to force checking for migration 0027 strings 2024-07-15 22:25:25 +02:00
Alexandre Aubin
52443174a0 Rename 0027_migrate_to_bookworm.py.disabled -> 0027_migrate_to_bookworm.py 2024-07-15 22:24:26 +02:00
Alexandre Aubin
f16011a138 Remove reference to rspamd, rspamd is to become an app 2024-07-15 22:23:59 +02:00
Alexandre Aubin
262a3c5cf2 Merge remote-tracking branch 'origin/dev' into bookworm 2024-07-15 16:54:21 +02:00
Alexandre Aubin
128df3d804
Update services.yml 2024-07-11 11:35:28 +02:00
Alexandre Aubin
3a06241956
Merge pull request #1905 from YunoHost/auth_header-to-false
ssowatconf: change auth_header from None to false
2024-07-11 11:14:47 +02:00
Kayou
4f7fa32f34
ssowatconf: change auth_header from None to false 2024-07-11 11:09:42 +02:00
Alexandre Aubin
c8183188ed Gotta depend on python3-jinja2 >= 3.0 to prevent issues with markupsaf 2024-07-06 17:25:35 +02:00
Alexandre Aubin
6120a5a8e4 YunoHost has a hard dependence on python 3.11 because of type hints syntax ... Also ${python3:Depends} and ${misc:Depends} don't do anything special in our context 2024-07-06 17:04:08 +02:00
Alexandre Aubin
7f7bafb339 Merge branch 'migrate-to-bookworm' into bookworm 2024-07-06 16:58:42 +02:00
Alexandre Aubin
5429885e0a Fix i18n strings? 2024-07-03 23:41:57 +02:00
Alexandre Aubin
30c512fc91 Fix i18n messages for bullseye->bookworm 2024-07-03 23:26:33 +02:00
Alexandre Aubin
edaffcf743 Adapt venv-rebuild migration for bookworm 2024-07-03 23:15:28 +02:00
Alexandre Aubin
3d05ff1d0e Cleanup old migrations 2024-07-03 22:07:06 +02:00
Alexandre Aubin
4b8506f71f Add migration for postgresql 13->15 after migrating to bookworm 2024-07-03 20:20:16 +02:00
Alexandre Aubin
1a85521f1f Didnt realize this line could be removed during previous merge 2024-07-03 19:09:04 +02:00
Alexandre Aubin
8366e4b7c4 Merge branch 'migrate-to-bookworm' into bookworm 2024-07-03 17:27:09 +02:00
Alexandre Aubin
b523089e48
Merge pull request #1887 from YunoHost/fix_yarn_test
Test resources with influxdb instead of yarn that is installed by default now
2024-06-30 17:42:23 +02:00
9cf8a7b6a7 Test resources with influxdb instead of yarn that is installed by default now 2024-06-30 17:38:25 +02:00
Alexandre Aubin
b661356783 Merge remote-tracking branch 'origin/dev' into bookworm 2024-06-30 00:23:58 +02:00
Alexandre Aubin
e13e9bc378 Merge remote-tracking branch 'origin/dev' into bookworm 2024-06-13 14:27:27 +02:00
Alexandre Aubin
bb4f9cc1da Merge remote-tracking branch 'origin/migrate-to-bookworm' into bookworm 2024-06-10 12:39:52 +02:00
Alexandre Aubin
caa26ee005 tests: remove old reliances on xmpp.main 2024-06-10 00:40:13 +02:00
Alexandre Aubin
2e59393943 ldap/permissions: add a migration to delete the legacy xmpp.main perm 2024-06-10 00:33:46 +02:00
Alexandre Aubin
cff89050df Remaining metronome trick to cleanup 2024-06-09 15:57:50 +02:00
Alexandre Aubin
37c99082f2
Update certificate.py: moar typo @_@ 2024-06-09 12:08:18 +02:00
Alexandre Aubin
d2259928ce
Update certificate.py: typo @_@ 2024-06-09 12:06:23 +02:00
Alexandre Aubin
1e527a8214
Merge pull request #1831 from YunoHost/handle-metronome-as-an-app
Handle metronome as an app
2024-06-09 10:55:41 +02:00
Alexandre Aubin
40778817ac Merge remote-tracking branch 'origin/bookworm' into handle-metronome-as-an-app 2024-06-08 16:35:53 +02:00
Alexandre Aubin
46372a0f22 dns+certs: add a new cert_alternate_names hook + improve custom_dns_rules hook 2024-06-08 16:35:44 +02:00
Alexandre Aubin
7c71bd8663 Merge remote-tracking branch 'origin/dev' into bookworm 2024-06-04 16:11:40 +02:00
Alexandre Aubin
b233ce1f15 Merge remote-tracking branch 'origin/dev' into bookworm 2024-05-22 13:14:04 +02:00
ljf (zamentur)
7674ba5ceb [fix] Forbidden keywords config panel 2024-05-22 07:14:17 +02:00
Alexandre Aubin
d4ef6461f3 Merge remote-tracking branch 'origin/dev' into bookworm 2024-05-19 21:01:34 +02:00
Alexandre Aubin
c02933cce4 Merge remote-tracking branch 'origin/dev' into bookworm 2024-05-19 20:52:43 +02:00
Alexandre Aubin
42d2f789cf Merge remote-tracking branch 'origin/dev' into bookworm 2024-05-19 20:47:27 +02:00
Alexandre Aubin
dc5c43255b
Merge pull request #1809 from orhtej2/fix_sso_domain
[bookworm] Return auth cookie valid for whole main domain.
2024-05-18 14:22:05 +02:00
Alexandre Aubin
4769242dc5 Yolodraft: handle metronome as an app 2024-05-11 14:50:46 +02:00
Alexandre Aubin
582350c145 mail: attempt to move to opendkim instead of rspamd for dkim signing/verify 2024-05-07 16:31:50 +02:00
Alexandre Aubin
2d8cd9f88a
Merge pull request #1822 from selfhoster1312/portal-without-apps
Allow users to access their own domain portal without app permission
2024-05-07 14:03:28 +02:00
selfhoster1312
5e406a55fa Allow users to access their own domain portal without app permission 2024-05-07 12:04:49 +02:00
tituspijean
3182aa85e7
Merge branch 'dev' into bookworm 2024-04-20 10:45:38 +02:00
Alexandre Aubin
7a077b5de9 Merge remote-tracking branch 'origin/dev' into bookworm 2024-04-11 15:51:19 +02:00
Alexandre Aubin
cc39fca559 Merge branch 'dev' into bookworm 2024-04-11 00:39:00 +02:00
Alexandre Aubin
2e3b4ae1f2 perf: add cache for system utils that fetch debian_version, debian_version_id, system_arch, system_virt 2024-04-10 23:08:31 +02:00
Alexandre Aubin
26bead701d Merge branch 'migrate-to-bookworm' into bookworm 2024-04-10 21:14:48 +02:00
Alexandre Aubin
458221e845 Merge remote-tracking branch 'origin/dev' into bookworm 2024-04-10 21:09:18 +02:00
orhtej2
10c6c807bf Return auth cookie valid for whole main domain. 2024-03-26 01:04:43 +01:00
Alexandre Aubin
2a4d5bfbc6 helpers/configpanel: fix assumption claquée au sol that $install_dir and $final_path always exist 2024-03-20 23:44:13 +01:00
Alexandre Aubin
7d640f84c6 ci: autoblack is now a github workflow 2024-03-14 09:22:32 +01:00
Alexandre Aubin
96494cbee4 apps: simplify env creation for config panel script, _make_environment_for_app_script already handles everything.. 2024-03-14 09:14:10 +01:00
Alexandre Aubin
11cabc0fe7 Merge remote-tracking branch 'origin/dev' into bookworm 2024-03-14 09:13:37 +01:00
Alexandre Aubin
76be0ee42c
Update 15-nginx: typo >_> 2024-02-05 19:30:51 +01:00
Alexandre Aubin
99e252107f Dafuq Aleks, we do need to send the SSO cookie on all route not just the portal API route 2024-02-04 15:18:48 +01:00
Alexandre Aubin
7f1dd865d7 Typo :| 2024-02-03 21:36:30 +01:00
Alexandre Aubin
c77d05e693 portal: store custom logos in a /usr/share/yunohost/customassets, and only store the file id which the front should then query as a regular asset 2024-02-03 21:07:45 +01:00
Alexandre Aubin
f248086fb6 nginx: nevermind applogos caching, nowadays nginx/browsers automatically cache static assets with etags etc ? 2024-02-03 20:28:41 +01:00
Alexandre Aubin
8823ef0a2c nginx: can't really delete the old yunohost_panel.conf.inc because it may be included by nginx app confs ~_~ 2024-02-03 20:06:10 +01:00
Alexandre Aubin
6958ea3b0f regenconf: more factorizing in yunohost hook 2024-02-03 20:00:13 +01:00
Alexandre Aubin
a47321e1bc Typo 2024-02-03 19:44:36 +01:00
Alexandre Aubin
402327d6ef regenconf: factorize all the dirs/perm stuff in the yunohost hook 2024-02-03 19:43:13 +01:00
Alexandre Aubin
ceace620da regenconf: factorize nginx regenconf a bit 2024-02-03 18:58:34 +01:00
Alexandre Aubin
ce529107be regenconf: remove unecessary/inconsistent check that script is ran as root... 2024-02-03 18:42:08 +01:00
Alexandre Aubin
41da1daf02 nginx: remove old 'yunohost_panel.conf' stuff 2024-02-03 18:39:25 +01:00
Alexandre Aubin
98701ebdab regenconf: the 'plain' subfolder thing for nginx conf is annoying, flatten things up 2024-02-03 18:36:55 +01:00
Alexandre Aubin
ca835534de portal: serve app logos from an sso-specific route (to keep separation of concern etc) 2024-02-03 18:24:31 +01:00
Alexandre Aubin
69cc6345a5 webadmin: add cache config for app logos 2024-02-03 18:21:02 +01:00
Alexandre Aubin
6a3c77eda1 auth: restrict cookies to the appropriate api 2024-02-03 17:29:19 +01:00
Alexandre Aubin
9a7ec301a6 configpanel: improve debugging/error message when pydantic fails to validate the options etc 2024-02-03 16:51:02 +01:00
Alexandre Aubin
b427783721 Make linter happy 2024-01-31 03:17:21 +01:00
Alexandre Aubin
ec8594a325 Zgrombpf 2024-01-31 03:16:07 +01:00
Alexandre Aubin
ddbd367085 Fix app resource test 2024-01-31 02:43:43 +01:00
Alexandre Aubin
133ce6e6b2 Fix permission test 2024-01-31 02:14:35 +01:00
Alexandre Aubin
b4b55fae54 Fix empty catalog test 2024-01-31 02:09:29 +01:00
Alexandre Aubin
e682fe9abd apps/portalconf: use description from local manifest + cases where the app aint in catalog or has no logo hash 2024-01-31 02:06:29 +01:00
Alexandre Aubin
c9a4838b5a tests/sso: add tests for subdomain and secondary 'main' domain 2024-01-31 01:35:37 +01:00
Alexandre Aubin
80d6a6f08d tests: fix/add tests for SSO 2024-01-31 00:16:26 +01:00
Alexandre Aubin
fc048f804e tests/sso: fix redirect test, gotta explicitly tell python to not follow 302s 2024-01-30 22:59:14 +01:00
Alexandre Aubin
61a43df169 Cleanup unused code 2024-01-30 19:53:32 +01:00
Alexandre Aubin
18df4bbc32 ssowatconf: replace use_remote_user_var_in_nginx_conf with protect_against_basic_auth_spoofing, and basic-with/without-password for the auth_header flag 2024-01-30 19:46:18 +01:00
Alexandre Aubin
d9daf111e6 helpers: fix pattern to wait for when fail2ban is starting/reloading 2024-01-30 19:18:06 +01:00
Alexandre Aubin
cc97efa033 helpers: remove pre-4.2 behavior for default file/folders permissions 2024-01-30 17:06:33 +01:00
Alexandre Aubin
6e85323a8f Unused imports 2024-01-27 18:08:25 +01:00
Alexandre Aubin
8bd2104722 Moar lazy loading 2024-01-27 16:16:14 +01:00
Alexandre Aubin
dda095dc15 Cleanup legacy 2024-01-27 16:13:57 +01:00
Alexandre Aubin
b33a47f27d broken imports ... + more lazy loading 2024-01-27 16:13:37 +01:00
Alexandre Aubin
6a01b657da appscatalog: this 'init' step is overengineered ... let's instead say the nominal case is that there's no apps_catalog.yml defined, and in this case we use the default catalog 2024-01-27 15:51:56 +01:00
Alexandre Aubin
2d42f59377 logs: remove the intermediate useless 'categories' directory, this is triggering me so much 2024-01-27 15:31:10 +01:00
Alexandre Aubin
902e65f9bc domain: don't regen the ssowat conf when changing the main domain (creates an issue during postinstall) 2024-01-27 15:23:22 +01:00
Alexandre Aubin
045869283c portalapi: don't leak the full list of users nor private apps 2024-01-22 21:39:54 +01:00
Alexandre Aubin
16d7f77f91 apps: checking that relevant services are up before app actions: the 'services' key is a super old thing from packaging v1 era, and nowadays mariadb/php/.. are likely to be installed on the fly, not pre-installed on the system anymore. This should be reworked someday 2024-01-22 21:19:56 +01:00
Alexandre Aubin
0796273be3 sso/portal: more tests 2024-01-22 19:52:25 +01:00
axolotle
7f53f56471 portal: add app's description + logo from catalog in portal settings 2024-01-19 13:33:24 +01:00
axolotle
56b5670e4c domaiiconfig: add portal search engine option 2024-01-19 13:31:21 +01:00
axolotle
3bb5702855 UrlOption: fix serialize HttpUrl to str in post validator so it can be saved 2024-01-19 13:22:31 +01:00
axolotle
94d16d6d76 configpanels: avoid settings being None when empty 2024-01-19 13:20:45 +01:00
Alexandre Aubin
13638b0aa8 Oopsies 2024-01-14 19:54:09 +01:00
Alexandre Aubin
d41d6549eb legacy: drop autopatching of PHP versions, nowadays Sury is here by default and offers more flexibility over which PHP versions may be installed e.g. even 5.6 can still be installed on Bookworm, but anyway only a ~handful of apps are still using 7.2 or lower 2024-01-14 19:41:54 +01:00
Alexandre Aubin
99ac76e7d6 Drop legacy snippet from the 3.x era 2024-01-14 19:36:03 +01:00
Alexandre Aubin
388c30c40f Drop a bunch of legacy stuff from the 4.x era 2024-01-14 18:58:57 +01:00
Alexandre Aubin
862e66c17e regenconf/dovecot: make sure the home folder for vmail user is created to prevent a warning 2024-01-14 18:47:17 +01:00
Alexandre Aubin
c9f2bb7911 debian: force the dependency of resolvconf to be about the concrete package, not openresolv/systemd-resolved which apparently nowadays 'provide' resolvconf but with different stuff under the hood ~_~ 2024-01-14 18:19:30 +01:00
Alexandre Aubin
d3b50db951 Unused import 2024-01-14 17:53:57 +01:00
Alexandre Aubin
e2aaf72076 Portal theme is no more as well, now handled on a per-main-domain basis 2024-01-14 17:36:05 +01:00
Alexandre Aubin
b6c55c9aa6 SSOwat's tile overlay is no more 2024-01-14 17:25:41 +01:00
Alexandre Aubin
0dcecf5f47 Remove rspamd from recommends, replace with a global setting similar to pop3 to enable/disable antispam 2024-01-14 17:19:52 +01:00
Alexandre Aubin
1cbc30e0d5 So the reason the 'enable pop3' thing is not working properly is because the config panel was spitting inconsistent boolean shit like 1, True or 'yes' depending on whatever... 2024-01-14 17:08:24 +01:00
Alexandre Aubin
5975dd4310 Merge remote-tracking branch 'origin/dev' into bookworm 2024-01-14 16:25:02 +01:00
Alexandre Aubin
3aa087ca04 debian/postinst: make sure /etc/yunohost/portal exists 2024-01-01 19:44:13 +01:00
Alexandre Aubin
0a01423408 Merge remote-tracking branch 'origin/dev' into bookworm 2023-12-28 02:57:12 +01:00
Alexandre Aubin
7eb1413d09 zgrmbl 2023-12-27 05:09:36 +01:00
Alexandre Aubin
570a22a31c Make linters happy 2023-12-27 04:28:08 +01:00
Alexandre Aubin
61551eb40d Fix tests in CI context / yunohost-api is down and it's expected 2023-12-27 04:24:37 +01:00
Alexandre Aubin
0856f27b46 Unused imports 2023-12-27 03:22:30 +01:00
Alexandre Aubin
665592374d user/password: move to passlib hash.sha512_crypt to generate password hashes to replace deprecated crypt lib 2023-12-27 03:18:48 +01:00
Alexandre Aubin
f505efc8bb password: utils/password.py is not used by ssowat anymore 2023-12-27 02:41:52 +01:00
Alexandre Aubin
7f02fcd985 portalapi/sso: add a first bunch of unit tests 2023-12-27 02:41:24 +01:00
Alexandre Aubin
29cac1791d tests: fix hardcoded domain / typo x_x 2023-12-26 19:00:44 +01:00
Alexandre Aubin
3070e504ad Make rspamd an optional dependency, because rspamd is only necessary when you really care about incoming mail, is resource-heavy, and for some reason some setups cant install libhyperscan which is required by rspamd 2023-12-26 17:52:08 +01:00
Alexandre Aubin
351d9361fa sso: use PCRE regexes instead of LUA regex 2023-12-23 20:40:20 +01:00
Alexandre Aubin
7e7a6845d5 portal-api: improve handling of ldap interfaces 2023-12-22 01:11:49 +01:00
Alexandre Aubin
2be1dccb91 mypy doesn't like the function attribute trick 2023-12-22 00:34:15 +01:00
Alexandre Aubin
6022be5ff1 Prevent unecessary import resulting in catastrophies + lazy-load the session secrets 2023-12-22 00:25:08 +01:00
Alexandre Aubin
38b3cfddd8 quality: make linter gods happy 2023-12-22 00:00:49 +01:00
Alexandre Aubin
c19e2b7b19 auth/portal/acl: allow admins to log on any main domain 2023-12-21 23:52:04 +01:00
Alexandre Aubin
746433c5d1 Whoopsies 2023-12-21 19:48:57 +01:00
Alexandre Aubin
d0f1d9201c auth/portal/acl : add 'user is allowed for domain X' mechanism, such that users can't log in or add mail aliases for a domain they aint allowed to access. The fact that they are able to access a domain is derived from the fact that they have access to at least one app on that domain (actually .. we may want to bypass this check for admins, otherwise this is gonna be hella confusing for fresh intalls). 2023-12-21 18:36:15 +01:00
Alexandre Aubin
20d914fd10 Update 'ssowat conf regenerated' message to reflect that SSO and portal are two slightly different thing 2023-12-21 17:28:38 +01:00
Alexandre Aubin
9a45a6ccf2 auth/quality: replace os.path stuff with Path from pathlib 2023-12-21 17:18:06 +01:00
Alexandre Aubin
c57a7a4cf0 Zrgrml 2023-12-19 20:08:41 +01:00
Alexandre Aubin
3922ba9c68 Implement similar cookie mechanism for admin api (compared to portal) with static secret (cookies aint invalidated by api restart) and rolling session validity 2023-12-19 20:01:40 +01:00
Alexandre Aubin
d1022b1a6c Merge remote-tracking branch 'origin/dev' into bookworm 2023-12-12 15:12:13 +01:00
Alexandre Aubin
05ea37d694 lazy-load crypt which is a deprecated lib to avoid having DepreciationWarnings all over the place 2023-12-12 15:11:32 +01:00
axolotle
1d734b5df5 form: fix SelectOption's choices coercing list to dict 2023-12-12 12:17:19 +01:00
Alexandre Aubin
9809de65f8 tests: fix permission tests 2023-12-08 09:10:03 +01:00
Alexandre Aubin
3765349436 tests: fix boring warning about domain_a.dev/domain_b.dev during permissions tests 2023-12-08 09:00:17 +01:00
Alexandre Aubin
fb52083b09 tests: more debug attempt + remove the boring 'other_domain' for many test where we don't really care about second domain yet this slow things stuff ... 2023-12-07 16:39:27 +01:00
Alexandre Aubin
8351d88da1 ci: yolotry to add more info to debug issue with sso check 2023-12-07 15:53:01 +01:00
axolotle
2db709e043 i18n: add domain configpanel help keys in expected keys + add/remove some keys 2023-12-07 14:28:08 +01:00
axolotle
544fe85773 i18n: rename pydantic errors + register in form file 2023-12-07 14:26:01 +01:00
axolotle
5563fd8ca0 tests:backuprestore: let hooks gracefully fake exec except 'restore' 2023-12-07 13:49:47 +01:00
axolotle
878944c7c1 form: fix pattern can be None 2023-12-02 17:24:42 +01:00
axolotle
dad366da61 Merge branch 'dev' into bookworm 2023-12-01 18:46:39 +01:00
axolotle
cdc703a48f form: add pydantic errors translations 2023-12-01 18:25:22 +01:00
axolotle
719ffe387e tests:options: add small test for pattern 2023-12-01 18:24:29 +01:00
axolotle
3f320a2358 portal:auth: samesite=None in dev mode 2023-11-30 14:04:13 +01:00
axolotle
246c513796 portal:auth: remove touch in delete_session_cookie 2023-11-29 14:32:11 +01:00
axolotle
6f9203c98c form:FileOption: fix cli file check 2023-11-29 14:09:36 +01:00
axolotle
c5758bcd30 tests:questions: reflect changes of patch_users 2023-11-29 14:08:42 +01:00
Alexandre Aubin
29a452c1d3 ci: warnings about 'not identify correctly the dns zone for domain' driving me crazy² 2023-11-29 00:28:17 +01:00
Alexandre Aubin
a7553501b0 ci: warnings about 'not identify correctly the dns zone for domain' driving me crazy 2023-11-29 00:26:19 +01:00
Alexandre Aubin
60b7f63afa ci: move lint stage as first stage, require invalidcode to pass before running builds 2023-11-29 00:11:33 +01:00
Alexandre Aubin
35c809a726 ci: simplify 'test actionsmap' job, move it to linting 2023-11-28 23:58:50 +01:00
Alexandre Aubin
a0d6c9a032 ci: remove tmp profiling stuff 2023-11-28 23:52:29 +01:00
Alexandre Aubin
e7379a7ec3 ci: whoopsies stages must be declared in the other file 2023-11-28 23:37:40 +01:00
Alexandre Aubin
aaaea0dce2 ci: rework the translation+doc stages, have a 'bot' stage for everything that is likely to create a PR instead 2023-11-28 23:30:25 +01:00
Alexandre Aubin
0eccb7e46b ci: disable 'full-test' which is a huge pain, always run every 'test' jobs instead 2023-11-28 23:20:08 +01:00
Alexandre Aubin
16391d7374 perf: lazyloading settings_get + pass all the global settings as an env variable to the regenconf to prevent having to 'yunohost settings get' like ten times ... reduces the regenconf runtime from 35s to 23s on my machine 2023-11-28 21:12:03 +01:00
Alexandre Aubin
9a4b0e422d quality: unused import, missing import 2023-11-28 20:19:06 +01:00
Alexandre Aubin
24741de4d9 portalapi: turns out ssowat (as www-data) needs to be able to validate that the session file exists 2023-11-28 19:15:33 +01:00
Alexandre Aubin
d7855fc9a7 portalapi: propagate changes to fail2ban config 2023-11-28 18:40:49 +01:00
Alexandre Aubin
356c081a4f portalapi: implement a proper expiration/prolong mechanism for session cookies 2023-11-28 18:40:49 +01:00
axolotle
213d6416b6 test:permissions: update sso url and credentials structure 2023-11-28 16:26:44 +01:00
axolotle
2459834c1c tests:permissions: add an admin user 2023-11-28 16:10:25 +01:00
axolotle
c80feaeed3 tests: show_tile + label no longer in ssowat conf file 2023-11-28 15:46:41 +01:00
Alexandre Aubin
ed7c626c28
Merge pull request #1744 from YunoHost/lazyloadconfigpanel
perf: improve perf for a bunch of operations by lazy import + lazy define of config-panel related stuff
2023-11-28 14:46:16 +01:00
axolotle
5b5527a279 app:config: fix indentation for file content 2023-11-28 14:41:38 +01:00
Alexandre Aubin
3dda3bc4d5 perf: improve perf for a bunch of operations by lazy import + lazy define of config-panel related stuff 2023-11-28 14:31:38 +01:00
axolotle
650c0136f2 form:UserOption: merge choices and default into root validator with first admin user as default 2023-11-26 18:29:43 +01:00
axolotle
4a270b88b6 quality: fix lint + some formatting 2023-11-26 17:42:48 +01:00
axolotle
45b36dae05 domain: reset portal_logo value even if file has already been removed 2023-11-26 17:12:58 +01:00
axolotle
d28b6e96c8 configpanel: raise when unknown filter key 2023-11-26 17:01:38 +01:00
axolotle
25e23ce963 portal: reflect changes of splitting user form into info and password 2023-11-25 21:39:31 +01:00
axolotle
c8d0990e7b fix: pop 'portal_logo' when resaving settings 2023-11-25 21:38:33 +01:00
axolotle
e5a593a4bb fix: FileOption return already saved and hashed filepath 2023-11-25 21:37:29 +01:00
Alexandre Aubin
321aea4171 yolo: try to profile what's taking up so much time in tests... 2023-11-25 02:03:42 +01:00
Alexandre Aubin
8293388975 Merge remote-tracking branch 'origin/dev' into bookworm 2023-11-24 22:52:06 +01:00
Alexandre Aubin
c216a3f246 Merge remote-tracking branch 'origin/dev' into bookworm 2023-11-24 22:35:25 +01:00
axolotle
7e6fea440e quality: fix FileOption validator typing 2023-11-24 16:23:04 +01:00
Alexandre Aubin
b7882c9323 quality: fix obvious linter issues 2023-11-24 16:12:54 +01:00
axolotle
91f4e5fa42 domainconfig: add portal custom intros 2023-11-23 15:58:23 +01:00
axolotle
0095549b18 i18n: add domain config portal translations 2023-11-23 15:57:26 +01:00
axolotle
b6f7967758 domain:config: handle "portal_logo" with "python" mode and save content in portal settings 2023-11-17 17:30:01 +01:00
axolotle
2b75c8f036 form:FileOption: add file "accept" validation handling 2023-11-17 17:28:25 +01:00
axolotle
4dc9d35304 form:FileOption: add mode "bash" versus "python" validators 2023-11-17 17:27:24 +01:00
axolotle
64e2c3177c form: add "mode" to BaseOption to distinguish "bash" and "python" serialization 2023-11-17 17:21:34 +01:00
Alexandre Aubin
566f5d29a7 domain/portal: try to re-implement portal logo 2023-11-13 19:02:25 +01:00
axolotle
90aa6b86f1 form:BaseChoicesOption: do not declare choices to allow other related fields to come first in subclasses 2023-11-13 16:51:25 +01:00
axolotle
d7166bf77f portal: more explicit errors with path 2023-11-13 16:48:56 +01:00
Alexandre Aubin
587d729d60 portalapi: tweak ldap management to handle anonymous queries, eg to fetch domain list as ynh-portal 2023-11-13 15:39:38 +01:00
Alexandre Aubin
7fe950d11e Merge remote-tracking branch 'origin/dev' into bookworm 2023-11-12 16:45:41 +01:00
axolotle
d36ca72887 fix: some test apps has empty string domain 2023-11-09 17:40:04 +01:00
axolotle
5e81579c31 form: TagOption: add icon prop 2023-11-09 17:32:02 +01:00
axolotle
03fc739b3c domain: add _get_raw_domain_settings to read settings directly + use it in app_info to avoid infinite recursion 2023-11-09 15:49:19 +01:00
axolotle
5a655ba8cf domain:configpanel: update recovery_password check to new configpanel syntax 2023-11-09 14:56:01 +01:00
axolotle
ec2ffe6813 configpanel: remove unused arg 'config' from _get_raw_settings() 2023-11-09 14:52:58 +01:00
axolotle
6bcc3dd1c0 typing: fix logger typing + ignore weird constructors 2023-10-31 15:07:03 +01:00
axolotle
a924379774 Merge remote-tracking branch 'origin/dev' into bookworm 2023-10-31 03:11:49 +01:00
axolotle
004f44ed2d configpanel: add bind prop to SectionModel + PanelModel 2023-10-31 03:08:53 +01:00
axolotle
bfba939927 Merge remote-tracking branch 'origin/dev' into bookworm 2023-10-31 02:57:26 +01:00
Alexandre Aubin
5a3fe5460b quality: unused import 2023-10-30 19:06:44 +01:00
Alexandre Aubin
1acaf2af2e
Merge pull request #1653 from YunoHost/options-doc
ConfigPanel and app install form Options documentation
2023-10-30 19:05:56 +01:00
Alexandre Aubin
0957d31c14 ci/doc: add call to new configpanel/form doc generator, similar to what's done for helpers and app resources 2023-10-30 18:50:48 +01:00
Alexandre Aubin
f02538cef0 doc: iterate on configpanel/form documentation 2023-10-30 18:39:31 +01:00
Alexandre Aubin
8aee337d0f regenconf/portal: fix attempt to chown before the user is created 2023-10-30 17:04:58 +01:00
Alexandre Aubin
093c707eb6
Merge pull request #1677 from YunoHost/pydantic
ConfigPanel: switch to pydantic 3/3
2023-10-30 15:19:17 +01:00
axolotle
9423168aaf configpanels: fix app is_default + dns alert style 2023-10-30 15:17:01 +01:00
Alexandre Aubin
e4182bb362 debian: require moulinette, ssowat, yunohost-portal to be >= 12.0 2023-10-30 15:12:51 +01:00
Alexandre Aubin
418df4c05f debian: move yunohost-portal to 'Recommends' ... mainly to bypass issue on the CI, but also because it sounds legit ... not 100% about this ? 2023-10-30 15:12:51 +01:00
Alexandre Aubin
7c89c2c995
Merge pull request #1721 from YunoHost/fix-dump_script_log_extract_for_debugging
Fix dump script log extract for debugging
2023-10-30 14:01:31 +01:00
Kay0u
7f954af6b6 fix an error in dump_script_log_extract_for_debugging 2023-10-30 13:59:59 +01:00
axolotle
3faa574267 configpanel: add proper schema definition 2023-10-25 15:07:31 +02:00
axolotle
c4c79c61fe configpanel: forbid extra props on BaseOption + accordingly fix tests 2023-10-25 15:06:10 +02:00
axolotle
02619e8284 doc:config fix missing aleks additions 2023-10-24 15:05:26 +02:00
axolotle
b80868e967 doc:config: misc cosmetics fix 2023-10-24 14:06:16 +02:00
axolotle
ee72d2f463 doc:config: add ljf's advanced config panel doc 2023-10-23 19:05:23 +02:00
axolotle
d676348d35 doc: fix page routes and inconsistencies 2023-10-23 17:14:44 +02:00
axolotle
b3167ba2e8 doc:configpanel: add ConfigPanel doc with part of lfj comment in app example_ynh 2023-10-23 14:15:25 +02:00
axolotle
900f462791 doc:form: complete with ljf comments found in app example 2023-10-23 14:15:25 +02:00
axolotle
1221fd1458 doc:options: add documentation and generator for configpanel/manifest options 2023-10-23 14:15:25 +02:00
axolotle
9134515604 domain:config: make 'registrar' info a frozen input since an alert has no value 2023-10-22 17:53:50 +02:00
axolotle
3a31984e3c configpanel: allow other ConfigPanels to have no settings defined 2023-10-22 17:51:04 +02:00
axolotle
e7b43c763c configpanel: do not raise error if no settings file 2023-10-22 17:49:08 +02:00
axolotle
66cb855c0c domain: type fix 2023-10-22 17:47:43 +02:00
axolotle
3cae07970e form: remove no longer used hydrate_option_type method 2023-10-22 15:50:32 +02:00
axolotle
3a5d353c4b form: force option type to 'select' if there's 'choices' 2023-10-22 15:50:32 +02:00
axolotle
3f417bb9b3 tests: update error instance in tests to YunohostError for packaging errors 2023-10-22 15:50:32 +02:00
axolotle
ef860ee6ee form: default type to "select" if choices in option 2023-10-22 15:50:32 +02:00
axolotle
6953a8bf15 configpanel: quick fix option typing 2023-10-22 15:50:30 +02:00
axolotle
2f4c88ec55 form: parse pydantic error in logging 2023-10-22 15:49:29 +02:00
axolotle
51d302bf18 configpanel: is_action_section as attr 2023-10-22 15:49:29 +02:00
axolotle
d370cb0b24 configpanel: add value in options dict for config get --full 2023-10-22 15:49:29 +02:00
axolotle
48f882ecd3 form+configpanel: reflect Section optional value to all its Options 2023-10-22 15:49:29 +02:00
axolotle
fccb291d78 form: readd pattern to path 2023-10-22 15:49:29 +02:00
axolotle
bd9bf29a88 debian: add python3-pydantic + python3-email-validator dependencies 2023-10-22 15:49:27 +02:00
axolotle
b778aaf780 form: remove ChoosableOptions for now 2023-10-22 15:48:07 +02:00
axolotle
6bef4b1e0e app: remove call of 'domain_config_get' to avoid infinite recursion 2023-10-22 15:48:07 +02:00
axolotle
2a28e289ad form: rework 'hydrate_questions...' with a new 'parse_raw_options' that parse and validate options 2023-10-22 15:48:07 +02:00
axolotle
37b4eb956d typing: add missing type + misc typing fixes 2023-10-22 15:48:06 +02:00
axolotle
54cc23c90c config: update SettingsConfigPanel.reset 2023-10-22 15:46:57 +02:00
axolotle
b45515049d config: fix wrong diff logic on settings apply 2023-10-22 15:46:57 +02:00
axolotle
98ec5448f2 form: cli retries as variable to be patched in tests 2023-10-22 15:46:57 +02:00
axolotle
98d3b4ffc8 form: rework context/values/hooks in prompt_or_validate_form 2023-10-22 15:46:57 +02:00
axolotle
73b795be1d config: readd value has been initialized + change test removed value from settings since boolean has a native default value 2023-10-22 15:46:57 +02:00
axolotle
f087a6b967 config: normalize get option value 2023-10-22 15:46:57 +02:00
axolotle
25ccbd5f78 configpanel: quickly update list_actions 2023-10-22 15:46:57 +02:00
axolotle
15c827908f configpanel: update run_action 2023-10-22 15:46:57 +02:00
axolotle
6b3691ce53 configpanel: update set 2023-10-22 15:46:57 +02:00
axolotle
5f9ea58313 configpanel: update _apply 2023-10-22 15:46:55 +02:00
axolotle
7a60703ef5 configpanel: update _ask 2023-10-22 15:30:02 +02:00
axolotle
2c35dcbb24 configpanel: update _reload_services 2023-10-22 15:29:13 +02:00
axolotle
f1038de56d form: fix entities validators order for filter and apply the right default 2023-10-22 15:29:12 +02:00
axolotle
dbaea019fe form+config: replace _parse_pre_answered method with generic function 2023-10-22 15:28:14 +02:00
axolotle
a92e22b653 config: rework get method 2023-10-22 15:27:16 +02:00
axolotle
80dbd6dac4 form: rework entities validators to avoid multiple calls to them 2023-10-22 15:21:21 +02:00
axolotle
02948ad49c config: rework config+settings getter methods 2023-10-22 15:19:32 +02:00
axolotle
564a66de2f configpanel: add config panel models 2023-10-22 15:15:14 +02:00
axolotle
bec34b92b0 form: add reserved "id" validator 2023-10-22 15:13:13 +02:00
axolotle
774b11cbbe form: add legacy "name" attr 2023-10-22 15:13:13 +02:00
axolotle
a574855a03 form: fix forbidden readonly type 2023-10-22 15:13:13 +02:00
axolotle
582b1ed311 form: add translating method 2023-10-22 15:13:13 +02:00
axolotle
3ff6e6ed96 app: update app_install 2023-10-22 15:13:12 +02:00
axolotle
c428ba616a test:options: update tests results to pydantic parsing 2023-10-22 15:07:54 +02:00
axolotle
ec5da99a79 form: rework pre + post options validators 2023-10-22 15:07:54 +02:00
axolotle
3943774811 form: add dynamic annotation getters 2023-10-22 15:07:52 +02:00
axolotle
89ae5e654d form: update asking flow, separate form and options 2023-10-22 15:06:51 +02:00
axolotle
f5c56db10e form: use pydantic BaseModel in Options and add some validators 2023-10-22 15:02:10 +02:00
axolotle
5bd8680847 domain:config: restrict portal options to topest domains 2023-10-19 18:39:15 +02:00
axolotle
163dd4d359 domain:config: remove 'portal_logo' for now 2023-10-19 18:28:29 +02:00
axolotle
6f085ad255 conf_regen:yunohost: repeat init portal setup in post hook 2023-10-19 14:33:52 +02:00
axolotle
2b5726f4a8 portal: update settings reading from new config file 2023-10-18 18:36:07 +02:00
axolotle
9d21501648 domain:config: update portal option saving 2023-10-18 18:34:25 +02:00
axolotle
8d366e67b0 app_ssowatconf: generate per domain portal config with available apps 2023-10-18 18:29:55 +02:00
axolotle
827fbe337d conf_regen:yunohost: setup /etc/yunohost/portal 2023-10-18 18:21:03 +02:00
axolotle
c577125363 portal: temp disable 'show_other_domains_apps' settings due to missing domain info in ldap 2023-10-17 14:46:16 +02:00
axolotle
d65cca5ab1 portal: fix decode error 2023-10-17 14:15:59 +02:00
axolotle
089e0001c2 portal: retreive app permissions from ldap 2023-10-17 14:15:22 +02:00
Alexandre Aubin
a0ce7c2d28 ssowatconf: drop unused redirected_regex mechanism + we don't need the label+show_tile info in ssowat conf anymore 2023-10-07 17:40:06 +02:00
Alexandre Aubin
8036226935 Typo 2023-10-07 17:12:26 +02:00
Alexandre Aubin
fae3b676ea Getting crazy about the ssowat/nginx stupid issue ... 2023-10-06 17:22:01 +02:00
Alexandre Aubin
0548af0c25 ci: add git status to debug what commit exactly is used during builds ... 2023-10-06 14:11:38 +02:00
Alexandre Aubin
2fc2acea51 portalapi: misc fixes related to logging, edgecases 2023-10-06 14:11:38 +02:00
Alexandre Aubin
385c131d0c regenconf: fix dummy warning 2023-09-29 16:53:18 +02:00
Alexandre Aubin
814696e9c1 portal: redirect to $host/yunohost/admin by default (cf recent commit in ssowat) 2023-09-29 14:34:33 +02:00
Alexandre Aubin
127b6121d1 meh 2023-09-27 22:29:27 +02:00
Alexandre Aubin
d3418479a2 fix remaining log.getActionLogger 2023-09-27 22:25:44 +02:00
Alexandre Aubin
f617b97d80
portal/ssowat: fix conf initialization 2023-09-27 22:08:26 +02:00
Alexandre Aubin
b61a16421b portal-api: fix cookie secret initialization 2023-09-27 20:51:45 +02:00
Alexandre Aubin
a0dbf6a5b0 portal: improve domain setting fetch + set show_other_domains_apps to false by default ? 2023-09-27 20:40:50 +02:00
Alexandre Aubin
a4366e88fc
Merge pull request #1387 from YunoHost/portal-api
WIP : New portal API to partially replace SSOwat
2023-09-27 19:33:07 +02:00
Alexandre Aubin
9e87ea88df portal-api: improve semantic for yunohost public portal stuff 2023-09-27 19:30:55 +02:00
Alexandre Aubin
db30b3acb8
Merge branch 'bookworm' into portal-api 2023-09-27 18:57:02 +02:00
Alexandre Aubin
883bb2b498 Merge remote-tracking branch 'origin/dev' into bookworm 2023-09-27 17:56:48 +02:00
Alexandre Aubin
8a72bac884
Merge pull request #1692 from YunoHost/logging-is-a-mess
Moulinette logging is an unecessarily complex mess, episode 57682
2023-09-27 17:45:21 +02:00
Kay0u
ea981ee4a6
Merge branch 'bookworm' of github.com:YunoHost/yunohost into bookworm 2023-09-08 23:50:37 +02:00
Alexandre Aubin
a16f54ea96
Merge pull request #1711 from YunoHost/update-fail2ban-jail-conf
Update fail2ban jail conf
2023-09-08 23:50:34 +02:00
Kay0u
142fad4b78
typo 2023-09-08 23:50:30 +02:00
Kay0u
aed8ecb645
do not skip tests from 11.2 2023-09-08 23:47:57 +02:00
Kay0u
e77e9a0a9a
backup/restore tests from 11.2 2023-09-08 23:13:38 +02:00
Kayou
2bd3dd2bba
set maxretry to 10 2023-09-08 22:31:08 +02:00
Kay0u
d0b65d5661
revert important variables in fail2ban jail.conf 2023-09-08 15:17:25 +02:00
Kay0u
8eb2e72282
Update Fail2ban jail.conf file from https://sources.debian.org/src/fail2ban/1.0.2-2/config/jail.conf/ 2023-09-08 15:13:20 +02:00
axolotle
c641f099c5 add temp messy file handling for portal custom logo 2023-09-07 17:57:08 +02:00
axolotle
bfedf144b3 add settings getter + /public route to get settings and public apps 2023-09-04 16:31:58 +02:00
axolotle
2136db32b6 return domain from _get_user_infos 2023-09-04 16:27:06 +02:00
axolotle
20d21b57e0 wip: save portal configpanel options in separate file .portal.yml 2023-09-04 16:24:01 +02:00
axolotle
a1a47e5221 update config_domain.toml with portal options 2023-09-04 16:21:50 +02:00
axolotle
5562b61db0 add 'list_portal' AppOption modifier to add portal as a possible choice 2023-09-04 16:20:29 +02:00
axolotle
0645d18e67 add host as session cookie info 2023-09-04 16:19:07 +02:00
axolotle
8f0f85b722 merge update_password with update 2023-08-29 16:28:32 +02:00
Alexandre Aubin
a7580df7a9
Merge pull request #1701 from selfhoster1312/sso-csp-inline
Allow inline scripts for yunohost-portal (nginx CSP)
2023-08-15 14:18:45 +02:00
selfhoster1312
26d4d9420c Allow inline scripts for yunohost-portal (nginx CSP) 2023-08-15 14:12:08 +02:00
Alexandre Aubin
741caebdda
Merge pull request #1700 from selfhoster1312/decode-jwt
Serialize the JWT token to a cookie string instead of failing
2023-08-15 12:27:16 +02:00
selfhoster1312
101b5704c4 Serialize the JWT token to a cookie string instead of failing 2023-08-15 12:23:56 +02:00
Alexandre Aubin
dafae50e8a
Merge pull request #1698 from selfhoster1312/portal-api
Handle both cookies in the same way (please let me logout)
2023-08-13 23:42:19 +02:00
selfhoster1312
6f8b3fd57f Handle both cookies in the same way (please let me logout) 2023-08-13 23:11:31 +02:00
axolotle
db1670ca5d add temp portal_update_password 2023-08-01 16:28:25 +02:00
axolotle
c9092b2aad add portal_update to update user infos 2023-08-01 15:43:39 +02:00
axolotle
c3a4b7dabb add _get_user_infos helper 2023-08-01 15:18:48 +02:00
axolotle
ca6eb2cbaf lint 2023-08-01 15:15:52 +02:00
Alexandre Aubin
afd7b37ebc Tweak nginx portal conf to serve html/css/js/assets from /usr/share/yunohost/portal, similar to webadmin 2023-07-30 23:53:43 +02:00
Alexandre Aubin
5fd1850f19 Add dependency to new yunohost-portal debian package 2023-07-30 23:53:04 +02:00
Alexandre Aubin
09c5a4cfb9 admin and portalapi: propagate new configurable CORS mechanism from moulinette 2023-07-29 19:15:30 +02:00
Alexandre Aubin
704e42a6af portalapi: fix cookie not being deleted because maxage=-1 or something 2023-07-29 19:13:00 +02:00
Tagada
4385c886a4 Merge branch 'dev' into bookworm 2023-07-20 15:49:45 +02:00
Alexandre Aubin
2ece3b65f6 Moulinette logging is an unecessarily complex mess, episode 57682 2023-07-18 00:19:16 +02:00
Alexandre Aubin
ae37b5fc24 portalapi: Add new yunohost-portal-api to yunohost services 2023-07-17 19:47:24 +02:00
Alexandre Aubin
f69f87fa65 Merge remote-tracking branch 'origin/dev' into portal-api 2023-07-17 18:56:05 +02:00
Alexandre Aubin
4561f900df portal refactoring: update ssowat conf format with a dict mapping domains to portal urls. For now, let's have one portal per main/parent domain (which is anyway imposed by cookie management unless we reintroduce complex cross-domain authentication...) 2023-07-15 21:20:15 +02:00
Alexandre Aubin
ec96558c81 portalapi: add FIXMEs about auth layer 2023-07-15 20:07:18 +02:00
Alexandre Aubin
f4dfb56006 portal refactoring: the 'yunohost tile' thingy won't work anymore, gotta discuss what we want to do exactly 2023-07-15 16:01:03 +02:00
Alexandre Aubin
0cb673c125 portalapi: woopsies 2023-07-14 19:35:05 +02:00
Alexandre Aubin
5104c2a79f portalapi: add CORS headers ... though gotta revisit this later, I don't know what I'm doing 2023-07-14 19:11:32 +02:00
Alexandre Aubin
5e1d69a2cb portalapi: harden systemd service configuration 2023-07-14 18:55:33 +02:00
Alexandre Aubin
2c0f49cef3 portalapi: add groups and apps list in infos returned by GET /me 2023-07-14 04:44:03 +02:00
Alexandre Aubin
6c6dd318fb portalapi: implement encrypted password storage in the user's cookie using AES256 2023-07-11 22:39:22 +02:00
Alexandre Aubin
236e85eece apt: add signed-by clause to sury and yarn repo 2023-07-11 18:12:34 +02:00
Alexandre Aubin
f1200b81dc apt: always add yarn repo because it's annoying to have to deal with an extra repo in each nodejs app just to install a single package.. 2023-07-11 18:12:34 +02:00
Alexandre Aubin
9a5080ea16 portalapi: fix split or user/password in auth code 2023-07-11 17:49:25 +02:00
Alexandre Aubin
a1cf770e1b Merge branch 'dev' into portal-api 2023-07-11 17:11:02 +02:00
Alexandre Aubin
2f2ff6eb19
Simplify fpm add config helper (Bookworm) (#1685)
* Simplify ynh_add_fpm_config helper

* helpers: drop dedicated_service option in ynh_add_fpm_config
2023-07-11 15:58:59 +02:00
Alexandre Aubin
7ba6c37eb8 Merge branch '11.2' into bookworm 2023-07-11 15:56:52 +02:00
Alexandre Aubin
cab7667dcc misc: more boring irrelevant postgresql warnings to filter out 2023-07-04 19:48:55 +02:00
Alexandre Aubin
bdc296f858 Merge remote-tracking branch 'origin/dev' into bookworm 2023-07-04 18:10:25 +02:00
Alexandre Aubin
8a865daddd apps: add YNH_DEFAULT_PHP_VERSION in app's dict as a boring workaround/fix for apps using YNH_DEFAULT_PHP_VERSION in _common.sh *before* sourcing helpers ... 2023-06-19 16:04:31 +02:00
Alexandre Aubin
ced6d5c975 apps: fix version.parse now refusing to parse legacy version numbers 2023-06-18 15:48:14 +02:00
Alexandre Aubin
a673b3ed42 Postgresql is now version 15 2023-06-14 10:28:58 +02:00
Alexandre Aubin
8ac48ee09e Drop deprecated firstname/lastname in user_create/update + also drop old deprecated cert- commands 2023-06-14 08:04:16 +02:00
Alexandre Aubin
f6ab380730 helpers/php: Default PHP version in bookworm is now 8.2 2023-06-14 08:02:35 +02:00
Alexandre Aubin
efe3ace98d
Merge pull request #1619 from YunoHost/legacy_cleanup
WIP : Legacy cleanup (meant for Bookworm)
2023-06-13 21:36:37 +02:00
Alexandre Aubin
81b96ad6d4 tests: tmp tweaks to adapt for removed deprecated features 2023-06-13 21:30:20 +02:00
Alexandre Aubin
b4dcd0fb22 Merge branch 'bookworm' into legacy_cleanup 2023-06-13 21:30:01 +02:00
Alexandre Aubin
b6ae711dd7
Merge pull request #1666 from eldertek/fix-2090
[fix] Remove deprecated domain_dns_conf
2023-06-13 20:43:35 +02:00
Alexandre Aubin
194eb9c6c7 conf: Update ciphers for nginx, postfix, dovecot 2023-06-13 20:39:56 +02:00
Alexandre Aubin
c4c353843c Unused vars, unhappy linter gods 2023-06-13 14:57:55 +02:00
Alexandre Aubin
8728b2030c Remove migrations/0027_migrate_to_bookworm for now because it's triggering errors on the CI, at least half of it should be reworked, and it should be in a separated PR to target dev(=bullseye) 2023-06-13 14:57:55 +02:00
Alexandre Aubin
d1d6da8fcb Merge branch 'dev' into bookworm 2023-06-13 14:57:44 +02:00
Tagada
5a2570a5d6 Merge branch 'dev' into bookworm 2023-06-11 00:00:38 +02:00
Kayou
78cd79ec48
Update debian/changelog 2023-06-05 10:11:50 +02:00
ElderTek
23eaf609da remove deprecated 2023-05-25 00:00:07 +04:00
Alexandre Aubin
c319303612 Merge remote-tracking branch 'origin/dev' into bookworm 2023-05-22 20:58:20 +02:00
Kay0u
85b08e44c9
ci: preinstall more package 2023-05-22 15:29:21 +02:00
Alexandre Aubin
3b75485923 tests: somehow using 'Domain' as http header aint supported anymore, gotta use Host 2023-05-16 15:21:27 +02:00
Alexandre Aubin
5b9721eb23 tests: fix bad regex permission test because python3.11 now accepts ++ quantifier, so change the 'bad regex' trick 2023-05-16 15:17:03 +02:00
Alexandre Aubin
5564f7dc12 tests: fix remaining funky mocker.spy 2023-05-16 15:11:51 +02:00
Kay0u
734db1994c
ci: don't install any package with pip, it's supposed to be preinstalled 2023-05-16 11:30:56 +02:00
Alexandre Aubin
bed9ecc09e py39->py311 in tox 2023-05-15 22:12:55 +02:00
Alexandre Aubin
1af88b0c55 ci: force tox install during lint tasks 2023-05-15 19:06:32 +02:00
Alexandre Aubin
031c641b77 tests: fix spy on m18n.n which in some cases doesnt work anymore ... not sure why, bit confused ... 2023-05-15 18:51:18 +02:00
Alexandre Aubin
482f8f3443 backup: fix again backup hook for xmpp when data folder dont exist 2023-05-15 17:37:11 +02:00
Alexandre Aubin
774ac64770 Merge remote-tracking branch 'origin/dev' into bookworm 2023-05-15 17:26:17 +02:00
Alexandre Aubin
d0838cbe58 Merge remote-tracking branch 'origin/dev' into bookworm 2023-05-13 19:20:33 +02:00
Tagadda
691ce5eace fix: python3.11 now supports Possessive Quantifiers regex 2023-05-13 14:37:32 +00:00
Tagadda
f617287eb2 woops thanks codeql i guess 2023-05-05 23:58:30 +00:00
Tagadda
2dbe34c030 aaand mariadb-server ofc... 2023-05-05 23:44:46 +00:00
Tagadda
de3dd9436c create migration : s/bullseye/bookworm
s/buster/bullseye
yolo, needs some more cleanup
2023-05-05 23:40:17 +00:00
Tagadda
ea7bdb62ed mariadb-client needed by tests/test_app_resources.py 2023-05-05 22:24:43 +00:00
Tagadda
1135cf1b62 php-cli is needed for ynhtest_config.sh 2023-05-05 21:23:23 +00:00
Tagadda
8fb225f3ad remove some legacy pre-bullseye workarounds 2023-05-05 19:16:21 +00:00
Alexandre Aubin
0901298935 bookworm: add php7.x -> php8.2 autopatch 2023-05-05 20:18:19 +02:00
Alexandre Aubin
7fc7d188ad Fix XMPP stuff that may not exists 2023-05-05 20:11:16 +02:00
Alexandre Aubin
1fb3965e51 improve previous commit, use ynh_apt to have non-interactive apt etc 2023-05-05 20:10:52 +02:00
Alexandre Aubin
191520ebdd mysql: dirty/ugly patch to autoinstall mariadb-server when calling ynhmysql_setup_db when it's not installed 2023-05-05 19:22:37 +02:00
Kayou
30bd0e05b2
Update test.gitlab-ci.yml
oopsie
2023-05-05 16:38:53 +02:00
Kayou
859f9c05a5
Update test.gitlab-ci.yml
fix tests for bookworm, don't try this at home²
2023-05-05 16:37:33 +02:00
Alexandre Aubin
224f1b1730 firewall: fix upnpc.discover() behavior that somehow now trigger an exception when cant talk to upnp device 2023-05-05 00:09:09 +02:00
Alexandre Aubin
37eac5e121 Update changelog for 12.0.0 2023-05-04 20:31:14 +02:00
Alexandre Aubin
0ab7c952f1 bookworm/debian: adapt control file to bookworm 2023-05-04 20:11:10 +02:00
Alexandre Aubin
04eadd715c Kill old --package option and .ini for PHP FPM config 2023-02-28 18:55:47 +01:00
Alexandre Aubin
22681a4f24 Kill the old 'unprotected/protected/skipped' setting hell 2023-02-28 18:50:31 +01:00
Alexandre Aubin
58ffff556c Merge remote-tracking branch 'origin/dev' into portal-api 2022-08-09 18:22:32 +02:00
Alexandre Aubin
76eba6fc88 Fix log permission issue for yunohost-portal-api 2021-12-27 13:05:11 +01:00
Alexandre Aubin
bd564e6a53 Add systemd conf for new service yunohost-portal-api 2021-12-27 12:44:20 +01:00
Alexandre Aubin
45baaead36 Fix typo + unused import 2021-12-26 18:22:33 +01:00
Alexandre Aubin
62808152ee Cookie handling for the new portal API 2021-12-26 16:52:48 +01:00
Alexandre Aubin
1efb50c7ab Iterate on new portal API design: nginx config, cookie format, be able to open a non-root ldap session, 2021-12-25 15:44:14 +01:00
Alexandre Aubin
c01042b51d Merge remote-tracking branch 'origin/moar_session_management_changes' into portal-api 2021-12-25 15:42:02 +01:00
Alexandre Aubin
2845914d44 WIP: foundation for a new portal API to partially replace SSOwat 2021-12-04 03:27:23 +01:00
192 changed files with 7245 additions and 7302 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

53
bin/yunohost-portal-api Executable file
View file

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

View file

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

View file

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

View file

@ -13,9 +13,8 @@ protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %}
mail_plugins = $mail_plugins quota notify push_notification mail_plugins = $mail_plugins quota notify push_notification
############################################################################### ###############################################################################
# generated 2023-06-13, Mozilla Guideline v5.7, Dovecot 2.3.19, OpenSSL 3.0.9, intermediate configuration
# generated 2020-08-18, Mozilla Guideline v5.6, Dovecot 2.3.4, OpenSSL 1.1.1d, intermediate configuration # https://ssl-config.mozilla.org/#server=dovecot&version=2.3.19&config=intermediate&openssl=3.0.9&guideline=5.7
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.4&config=intermediate&openssl=1.1.1d&guideline=5.6
ssl = required ssl = required
@ -32,7 +31,7 @@ ssl_dh = </usr/share/yunohost/ffdhe2048.pem
# intermediate configuration # intermediate configuration
ssl_min_protocol = TLSv1.2 ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
ssl_prefer_server_ciphers = no ssl_prefer_server_ciphers = no
############################################################################### ###############################################################################
@ -142,18 +141,6 @@ plugin {
sieve_before = /etc/dovecot/global_script/ sieve_before = /etc/dovecot/global_script/
} }
plugin {
antispam_debug_target = syslog
antispam_verbose_debug = 0
antispam_backend = pipe
antispam_spam_pattern_ignorecase = junk;spam
antispam_trash_pattern_ignorecase = trash;papierkorb;deleted messages
antispam_pipe_program = /usr/bin/rspamc
antispam_pipe_program_args = -h;localhost:11334;-P;q1
antispam_pipe_program_spam_arg = learn_spam
antispam_pipe_program_notspam_arg = learn_ham
}
plugin { plugin {
quota = maildir:User quota quota = maildir:User quota
quota_rule2 = SPAM:ignore quota_rule2 = SPAM:ignore

View file

@ -18,7 +18,7 @@
# See man 5 jail.conf for details. # See man 5 jail.conf for details.
# #
# [DEFAULT] # [DEFAULT]
# bantime = 3600 # bantime = 1h
# #
# [sshd] # [sshd]
# enabled = true # enabled = true
@ -44,10 +44,52 @@ before = paths-debian.conf
# MISCELLANEOUS OPTIONS # MISCELLANEOUS OPTIONS
# #
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not # "bantime.increment" allows to use database for searching of previously banned ip's to increase a
# ban a host which matches an address in this list. Several addresses can be # default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
# defined using space (and/or comma) separator. #bantime.increment = true
ignoreip = 127.0.0.1/8
# "bantime.rndtime" is the max number of seconds using for mixing with random time
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
#bantime.rndtime =
# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
#bantime.maxtime =
# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
# default value of factor is 1 and with default value of formula, the ban time
# grows by 1, 2, 4, 8, 16 ...
#bantime.factor = 1
# "bantime.formula" used by default to calculate next value of ban time, default value below,
# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
#
# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)
# "bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
# previously ban count and given "bantime.factor" (for multipliers default is 1);
# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
#bantime.multipliers = 1 2 4 8 16 32 64
# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
#bantime.multipliers = 1 5 30 60 300 720 1440 2880
# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed
# cross over all jails, if false (default), only current jail of the ban IP will be searched
#bantime.overalljails = false
# --------------------
# "ignoreself" specifies whether the local resp. own IP addresses should be ignored
# (default is true). Fail2ban will not ban a host which matches such addresses.
#ignoreself = true
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
#ignoreip = 127.0.0.1/8 ::1
# External command that will take an tagged arguments to ignore, e.g. <ip>, # External command that will take an tagged arguments to ignore, e.g. <ip>,
# and return true if the IP is to be ignored. False otherwise. # and return true if the IP is to be ignored. False otherwise.
@ -56,15 +98,18 @@ ignoreip = 127.0.0.1/8
ignorecommand = ignorecommand =
# "bantime" is the number of seconds that a host is banned. # "bantime" is the number of seconds that a host is banned.
bantime = 600 bantime = 10m
# A host is banned if it has generated "maxretry" during the last "findtime" # A host is banned if it has generated "maxretry" during the last "findtime"
# seconds. # seconds.
findtime = 600 findtime = 10m
# "maxretry" is the number of failures before a host get banned. # "maxretry" is the number of failures before a host get banned.
maxretry = 10 maxretry = 10
# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
maxmatches = %(maxretry)s
# "backend" specifies the backend used to get files modification. # "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". # Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
# This option can be overridden in each jail as well. # This option can be overridden in each jail as well.
@ -113,10 +158,13 @@ logencoding = auto
enabled = false enabled = false
# "mode" defines the mode of the filter (see corresponding filter implementation for more info).
mode = normal
# "filter" defines the filter to use by the jail. # "filter" defines the filter to use by the jail.
# By default jails have names matching their filter name # By default jails have names matching their filter name
# #
filter = %(__name__)s filter = %(__name__)s[mode=%(mode)s]
# #
@ -140,7 +188,7 @@ mta = sendmail
# Default protocol # Default protocol
protocol = tcp protocol = tcp
# Specify chain where jumps would need to be added in iptables-* actions # Specify chain where jumps would need to be added in ban-actions expecting parameter chain
chain = INPUT chain = INPUT
# Ports to be banned # Ports to be banned
@ -161,51 +209,53 @@ banaction = iptables-multiport
banaction_allports = iptables-allports banaction_allports = iptables-allports
# The simplest action to take: ban only # The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report to the destemail. # ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] action_mw = %(action_)s
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] %(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report and relevant log lines # ban & send an e-mail with whois report and relevant log lines
# to the destemail. # to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] action_mwl = %(action_)s
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action # See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
# #
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines # ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
# to the destemail. # to the destemail.
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] action_xarf = %(action_)s
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"] xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
# ban & send a notification to one or more of the 50+ services supported by Apprise.
# See https://github.com/caronc/apprise/wiki for details on what is supported.
#
# You may optionally over-ride the default configuration line (containing the Apprise URLs)
# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise
# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration.
# action = %(action_)s
# apprise
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines # ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
# to the destemail. # to the destemail.
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"] action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
# Report block via blocklist.de fail2ban reporting service API # Report block via blocklist.de fail2ban reporting service API
# #
# See the IMPORTANT note in action.d/blocklist_de.conf for when to # See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
# use this action. Create a file jail.d/blocklist_de.local containing # Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
# [Init] # `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
# blocklist_de_apikey = {api key from registration] # in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in
# corresponding jail.d/my-jail.local file).
# #
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"] action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
# Report ban via badips.com, and use as blacklist # Report ban via abuseipdb.com.
# #
# See BadIPsAction docstring in config/action.d/badips.py for # See action.d/abuseipdb.conf for usage example and details.
# documentation for this action.
# #
# NOTE: This action relies on banaction being present on start and therefore action_abuseipdb = abuseipdb
# should be last action defined for a jail.
#
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
#
# Report ban via badips.com (uses action.d/badips.conf for reporting only)
#
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
# Choose default action. To change, just override value of 'action' with the # Choose default action. To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local # interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
@ -223,15 +273,10 @@ action = %(action_)s
[sshd] [sshd]
port = ssh # To use more aggressive sshd modes set filter parameter "mode" in jail.local:
logpath = %(sshd_log)s # normal (default), ddos, extra or aggressive (combines all).
backend = %(sshd_backend)s # See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode = normal
[sshd-ddos]
# This jail corresponds to the standard configuration in Fail2ban.
# The mail-whois action send a notification e-mail with a whois request
# in the body.
port = ssh port = ssh
logpath = %(sshd_log)s logpath = %(sshd_log)s
backend = %(sshd_backend)s backend = %(sshd_backend)s
@ -265,7 +310,7 @@ logpath = %(apache_error_log)s
# for email addresses. The mail outputs are buffered. # for email addresses. The mail outputs are buffered.
port = http,https port = http,https
logpath = %(apache_access_log)s logpath = %(apache_access_log)s
bantime = 172800 bantime = 48h
maxretry = 1 maxretry = 1
@ -301,7 +346,7 @@ maxretry = 2
port = http,https port = http,https
logpath = %(apache_access_log)s logpath = %(apache_access_log)s
maxretry = 1 maxretry = 1
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip> ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot <ip>
[apache-modsecurity] [apache-modsecurity]
@ -321,12 +366,15 @@ maxretry = 1
[openhab-auth] [openhab-auth]
filter = openhab filter = openhab
action = iptables-allports[name=NoAuthFailures] banaction = %(banaction_allports)s
logpath = /opt/openhab/logs/request.log logpath = /opt/openhab/logs/request.log
# To use more aggressive http-auth modes set filter parameter "mode" in jail.local:
# normal (default), aggressive (combines all), auth or fallback
# See "tests/files/logs/nginx-http-auth" or "filter.d/nginx-http-auth.conf" for usage example and details.
[nginx-http-auth] [nginx-http-auth]
# mode = normal
port = http,https port = http,https
logpath = %(nginx_error_log)s logpath = %(nginx_error_log)s
@ -342,8 +390,10 @@ logpath = %(nginx_error_log)s
port = http,https port = http,https
logpath = %(nginx_error_log)s logpath = %(nginx_error_log)s
maxretry = 2
[nginx-bad-request]
port = http,https
logpath = %(nginx_access_log)s
# Ban attackers that try to use PHP's URL-fopen() functionality # Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year # through GET/POST variables. - Experimental, with more than a year
@ -377,6 +427,8 @@ logpath = %(lighttpd_error_log)s
port = http,https port = http,https
logpath = %(roundcube_errors_log)s logpath = %(roundcube_errors_log)s
# Use following line in your jail.local if roundcube logs to journal.
#backend = %(syslog_backend)s
[openwebmail] [openwebmail]
@ -426,11 +478,13 @@ backend = %(syslog_backend)s
port = http,https port = http,https
logpath = /var/log/tomcat*/catalina.out logpath = /var/log/tomcat*/catalina.out
#logpath = /var/log/guacamole.log
[monit] [monit]
#Ban clients brute-forcing the monit gui login #Ban clients brute-forcing the monit gui login
port = 2812 port = 2812
logpath = /var/log/monit logpath = /var/log/monit
/var/log/monit.log
[webmin-auth] [webmin-auth]
@ -513,27 +567,29 @@ logpath = %(vsftpd_log)s
# ASSP SMTP Proxy Jail # ASSP SMTP Proxy Jail
[assp] [assp]
port = smtp,submission port = smtp,465,submission
logpath = /root/path/to/assp/logs/maillog.txt logpath = /root/path/to/assp/logs/maillog.txt
[courier-smtp] [courier-smtp]
port = smtp,submission port = smtp,465,submission
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[postfix] [postfix]
# To use another modes set filter parameter "mode" in jail.local:
port = smtp,submission mode = more
logpath = %(postfix_log)s port = smtp,465,submission
backend = %(postfix_backend)s logpath = %(postfix_log)s
backend = %(postfix_backend)s
[postfix-rbl] [postfix-rbl]
port = smtp,submission filter = postfix[mode=rbl]
port = smtp,465,submission
logpath = %(postfix_log)s logpath = %(postfix_log)s
backend = %(postfix_backend)s backend = %(postfix_backend)s
maxretry = 1 maxretry = 1
@ -541,14 +597,17 @@ maxretry = 1
[sendmail-auth] [sendmail-auth]
port = submission,smtp port = submission,465,smtp
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[sendmail-reject] [sendmail-reject]
# To use more aggressive modes set filter parameter "mode" in jail.local:
port = smtp,submission # normal (default), extra or aggressive
# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details.
#mode = normal
port = smtp,465,submission
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
@ -556,7 +615,7 @@ backend = %(syslog_backend)s
[qmail-rbl] [qmail-rbl]
filter = qmail filter = qmail
port = smtp,submission port = smtp,465,submission
logpath = /service/qmail/log/main/current logpath = /service/qmail/log/main/current
@ -564,14 +623,14 @@ logpath = /service/qmail/log/main/current
# but can be set by syslog_facility in the dovecot configuration. # but can be set by syslog_facility in the dovecot configuration.
[dovecot] [dovecot]
port = pop3,pop3s,imap,imaps,submission,sieve port = pop3,pop3s,imap,imaps,submission,465,sieve
logpath = %(dovecot_log)s logpath = %(dovecot_log)s
backend = %(dovecot_backend)s backend = %(dovecot_backend)s
[sieve] [sieve]
port = smtp,submission port = smtp,465,submission
logpath = %(dovecot_log)s logpath = %(dovecot_log)s
backend = %(dovecot_backend)s backend = %(dovecot_backend)s
@ -583,20 +642,21 @@ logpath = %(solidpop3d_log)s
[exim] [exim]
# see filter.d/exim.conf for further modes supported from filter:
port = smtp,submission #mode = normal
port = smtp,465,submission
logpath = %(exim_main_log)s logpath = %(exim_main_log)s
[exim-spam] [exim-spam]
port = smtp,submission port = smtp,465,submission
logpath = %(exim_main_log)s logpath = %(exim_main_log)s
[kerio] [kerio]
port = imap,smtp,imaps port = imap,smtp,imaps,465
logpath = /opt/kerio/mailserver/store/logs/security.log logpath = /opt/kerio/mailserver/store/logs/security.log
@ -607,14 +667,15 @@ logpath = /opt/kerio/mailserver/store/logs/security.log
[courier-auth] [courier-auth]
port = smtp,submission,imaps,pop3,pop3s port = smtp,465,submission,imap,imaps,pop3,pop3s
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[postfix-sasl] [postfix-sasl]
port = smtp,submission,imap,imaps,pop3,pop3s filter = postfix[mode=auth]
port = smtp,465,submission,imap,imaps,pop3,pop3s
# You might consider monitoring /var/log/mail.warn instead if you are # You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the # running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize. # "warn" level but overall at the smaller filesize.
@ -631,7 +692,7 @@ backend = %(syslog_backend)s
[squirrelmail] [squirrelmail]
port = smtp,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
@ -684,8 +745,8 @@ logpath = /var/log/named/security.log
[nsd] [nsd]
port = 53 port = 53
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
logpath = /var/log/nsd.log logpath = /var/log/nsd.log
@ -696,9 +757,8 @@ logpath = /var/log/nsd.log
[asterisk] [asterisk]
port = 5060,5061 port = 5060,5061
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
logpath = /var/log/asterisk/messages logpath = /var/log/asterisk/messages
maxretry = 10 maxretry = 10
@ -706,16 +766,22 @@ maxretry = 10
[freeswitch] [freeswitch]
port = 5060,5061 port = 5060,5061
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
logpath = /var/log/freeswitch.log logpath = /var/log/freeswitch.log
maxretry = 10 maxretry = 10
# enable adminlog; it will log to a file inside znc's directory by default.
[znc-adminlog]
port = 6667
logpath = /var/lib/znc/moddata/adminlog/znc.log
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or # To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
# equivalent section: # equivalent section:
# log-warning = 2 # log-warnings = 2
# #
# for syslog (daemon facility) # for syslog (daemon facility)
# [mysqld_safe] # [mysqld_safe]
@ -731,6 +797,14 @@ logpath = %(mysql_log)s
backend = %(mysql_backend)s backend = %(mysql_backend)s
[mssql-auth]
# Default configuration for Microsoft SQL Server for Linux
# See the 'mssql-conf' manpage how to change logpath or port
logpath = /var/opt/mssql/log/errorlog
port = 1433
filter = mssql-auth
# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf') # Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
[mongodb-auth] [mongodb-auth]
# change port when running with "--shardsvr" or "--configsvr" runtime operation # change port when running with "--shardsvr" or "--configsvr" runtime operation
@ -749,8 +823,8 @@ logpath = /var/log/mongodb/mongodb.log
logpath = /var/log/fail2ban.log logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s banaction = %(banaction_allports)s
bantime = 604800 ; 1 week bantime = 1w
findtime = 86400 ; 1 day findtime = 1d
# Generic filter for PAM. Has to be used with action which bans all # Generic filter for PAM. Has to be used with action which bans all
@ -786,11 +860,31 @@ logpath = /var/log/ejabberd/ejabberd.log
[counter-strike] [counter-strike]
logpath = /opt/cstrike/logs/L[0-9]*.log logpath = /opt/cstrike/logs/L[0-9]*.log
# Firewall: http://www.cstrike-planet.com/faq/6
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039 tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015 udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
%(banaction)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] %(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
[softethervpn]
port = 500,4500
protocol = udp
logpath = /usr/local/vpnserver/security_log/*/sec.log
[gitlab]
port = http,https
logpath = /var/log/gitlab/gitlab-rails/application.log
[grafana]
port = http,https
logpath = /var/log/grafana/grafana.log
[bitwarden]
port = http,https
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
[centreon]
port = http,https
logpath = /var/log/centreon/login.log
# consider low maxretry and a long bantime # consider low maxretry and a long bantime
# nobody except your own Nagios server should ever probe nrpe # nobody except your own Nagios server should ever probe nrpe
@ -824,7 +918,9 @@ filter = apache-pass[knocking_url="%(knocking_url)s"]
logpath = %(apache_access_log)s logpath = %(apache_access_log)s
blocktype = RETURN blocktype = RETURN
returntype = DROP returntype = DROP
bantime = 3600 action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
actionstart_on_demand=false, actionrepair_on_unban=true]
bantime = 1h
maxretry = 1 maxretry = 1
findtime = 1 findtime = 1
@ -832,8 +928,8 @@ findtime = 1
[murmur] [murmur]
# AKA mumble-server # AKA mumble-server
port = 64738 port = 64738
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol=tcp, chain="%(chain)s", actname=%(banaction)s-tcp] action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol=udp, chain="%(chain)s", actname=%(banaction)s-udp] %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
logpath = /var/log/mumble-server/mumble-server.log logpath = /var/log/mumble-server/mumble-server.log
@ -851,5 +947,34 @@ logpath = /var/log/haproxy.log
[slapd] [slapd]
port = ldap,ldaps port = ldap,ldaps
filter = slapd
logpath = /var/log/slapd.log logpath = /var/log/slapd.log
[domino-smtp]
port = smtp,ssmtp
logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
[phpmyadmin-syslog]
port = http,https
logpath = %(syslog_authpriv)s
backend = %(syslog_backend)s
[zoneminder]
# Zoneminder HTTP/HTTPS web interface auth
# Logs auth failures to apache2 error log
port = http,https
logpath = %(apache_error_log)s
[traefik-auth]
# to use 'traefik-auth' filter you have to configure your Traefik instance,
# see `filter.d/traefik-auth.conf` for details and service example.
port = http,https
logpath = /var/log/traefik/access.log
[scanlogd]
logpath = %(syslog_local0)s
banaction = %(banaction_allports)s
[monitorix]
port = 8080
logpath = /var/log/monitorix-httpd

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,16 +3,16 @@ ssl_session_cache shared:SSL:50m; # about 200000 sessions
ssl_session_tickets off; ssl_session_tickets off;
{% if compatibility == "modern" %} {% if compatibility == "modern" %}
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, modern configuration # generated 2023-06-13, Mozilla Guideline v5.7, nginx 1.22.1, OpenSSL 3.0.9, modern configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=modern&openssl=1.1.1d&guideline=5.6 # https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=modern&openssl=3.0.9&guideline=5.7
ssl_protocols TLSv1.3; ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off; ssl_prefer_server_ciphers off;
{% else %} {% else %}
# Ciphers with intermediate compatibility # Ciphers with intermediate compatibility
# generated 2020-08-14, Mozilla Guideline v5.6, nginx 1.14.2, OpenSSL 1.1.1d, intermediate configuration # generated 2023-06-13, Mozilla Guideline v5.7, nginx 1.22.1, OpenSSL 3.0.9, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6 # https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=intermediate&openssl=3.0.9&guideline=5.7
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off; ssl_prefer_server_ciphers off;
# Pre-defined FFDHE group (RFC 7919) # Pre-defined FFDHE group (RFC 7919)

View file

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

View file

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

View file

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

View file

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

View file

@ -30,8 +30,8 @@ smtpd_tls_chain_files =
tls_server_sni_maps = hash:/etc/postfix/sni tls_server_sni_maps = hash:/etc/postfix/sni
{% if compatibility == "intermediate" %} {% if compatibility == "intermediate" %}
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, intermediate configuration # generated 2023-06-13, Mozilla Guideline v5.7, Postfix 3.7.5, OpenSSL 3.0.9, intermediate configuration
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=intermediate&openssl=1.1.1d&guideline=5.6 # https://ssl-config.mozilla.org/#server=postfix&version=3.7.5&config=intermediate&openssl=3.0.9&guideline=5.7
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
@ -41,10 +41,10 @@ smtpd_tls_mandatory_ciphers = medium
# not actually 1024 bits, this applies to all DHE >= 1024 bits # not actually 1024 bits, this applies to all DHE >= 1024 bits
smtpd_tls_dh1024_param_file = /usr/share/yunohost/ffdhe2048.pem smtpd_tls_dh1024_param_file = /usr/share/yunohost/ffdhe2048.pem
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
{% else %} {% else %}
# generated 2020-08-18, Mozilla Guideline v5.6, Postfix 3.4.14, OpenSSL 1.1.1d, modern configuration # generated 2023-06-13, Mozilla Guideline v5.7, Postfix 3.7.5, OpenSSL 3.0.9, modern configuration
# https://ssl-config.mozilla.org/#server=postfix&version=3.4.14&config=modern&openssl=1.1.1d&guideline=5.6 # https://ssl-config.mozilla.org/#server=postfix&version=3.7.5&config=modern&openssl=3.0.9&guideline=5.7
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2 smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2
@ -182,9 +182,10 @@ smtp_header_checks = regexp:/etc/postfix/header_checks
smtp_reply_filter = pcre:/etc/postfix/smtp_reply_filter smtp_reply_filter = pcre:/etc/postfix/smtp_reply_filter
# Rmilter # Rmilter
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} {auth_type}
milter_protocol = 6 milter_protocol = 6
smtpd_milters = inet:localhost:11332 smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
# Skip email without checking if milter has died # Skip email without checking if milter has died
milter_default_action = accept milter_default_action = accept
@ -211,11 +212,3 @@ smtp_sasl_security_options = noanonymous
# where to find sasl_passwd # where to find sasl_passwd
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
{% endif %} {% endif %}
{% if backup_mx_domains != "" %}
# Backup MX (secondary MX)
relay_domains = $mydestination {{backup_mx_domains}}
relay_recipient_maps = hash:/etc/postfix/relay_recipients
maximal_queue_lifetime = 20d
{% endif %}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

69
debian/changelog vendored
View file

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

40
debian/control vendored
View file

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

1
debian/install vendored
View file

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

8
debian/postinst vendored
View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Entrypoint for the helpers scripts # Entrypoint for the helpers scripts
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Helpers version can be specified via an environment variable or default to 1. # Helpers version can be specified via an environment variable or default to 1.
YNH_HELPERS_VERSION=${YNH_HELPERS_VERSION:-1} YNH_HELPERS_VERSION=${YNH_HELPERS_VERSION:-1}
@ -21,7 +21,6 @@ case "$YNH_HELPERS_VERSION" in
*) *)
echo "Helpers are not available in version '$YNH_HELPERS_VERSION'." >&2 echo "Helpers are not available in version '$YNH_HELPERS_VERSION'." >&2
exit 1 exit 1
;;
esac esac
eval "$XTRACE_ENABLE" eval "$XTRACE_ENABLE"

View file

@ -7,49 +7,52 @@
# #
# Requires YunoHost version *.*.* or higher. # Requires YunoHost version *.*.* or higher.
ynh_install_apps() { ynh_install_apps() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=a local legacy_args=a
local -A args_array=([a]=apps=) local -A args_array=([a]=apps=)
local apps local apps
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# Split the list of apps in an array # Split the list of apps in an array
local apps_list=($(echo $apps | tr " " "\n")) local apps_list=($(echo $apps | tr " " "\n"))
local apps_dependencies="" local apps_dependencies=""
# For each app
for one_app_and_its_args in "${apps_list[@]}"
do
# Retrieve the name of the app (part before ?)
local one_app=$(cut -d "?" -f1 <<< "$one_app_and_its_args")
[ -z "$one_app" ] && ynh_die --message="You didn't provided a YunoHost app to install"
# For each app yunohost tools update apps
for one_app_and_its_args in "${apps_list[@]}"; do
# Retrieve the name of the app (part before ?) # Installing or upgrading the app depending if it's installed or not
local one_app=$(cut -d "?" -f1 <<< "$one_app_and_its_args") if ! yunohost app list --output-as json --quiet | jq -e --arg id $one_app '.apps[] | select(.id == $id)' >/dev/null
[ -z "$one_app" ] && ynh_die --message="You didn't provided a YunoHost app to install" then
# Retrieve the arguments of the app (part after ?)
local one_argument=""
if [[ "$one_app_and_its_args" == *"?"* ]]; then
one_argument=$(cut -d "?" -f2- <<< "$one_app_and_its_args")
one_argument="--args $one_argument"
fi
# Install the app with its arguments
yunohost app install $one_app $one_argument
else
# Upgrade the app
yunohost app upgrade $one_app
fi
yunohost tools update apps if [ ! -z "$apps_dependencies" ]
then
apps_dependencies="$apps_dependencies, $one_app"
else
apps_dependencies="$one_app"
fi
done
# Installing or upgrading the app depending if it's installed or not ynh_app_setting_set --app=$app --key=apps_dependencies --value="$apps_dependencies"
if ! yunohost app list --output-as json --quiet | jq -e --arg id $one_app '.apps[] | select(.id == $id)' > /dev/null; then
# Retrieve the arguments of the app (part after ?)
local one_argument=""
if [[ "$one_app_and_its_args" == *"?"* ]]; then
one_argument=$(cut -d "?" -f2- <<< "$one_app_and_its_args")
one_argument="--args $one_argument"
fi
# Install the app with its arguments
yunohost app install $one_app $one_argument
else
# Upgrade the app
yunohost app upgrade $one_app
fi
if [ ! -z "$apps_dependencies" ]; then
apps_dependencies="$apps_dependencies, $one_app"
else
apps_dependencies="$one_app"
fi
done
ynh_app_setting_set --app=$app --key=apps_dependencies --value="$apps_dependencies"
} }
# Remove other YunoHost apps # Remove other YunoHost apps
@ -60,47 +63,53 @@ ynh_install_apps() {
# #
# Requires YunoHost version *.*.* or higher. # Requires YunoHost version *.*.* or higher.
ynh_remove_apps() { ynh_remove_apps() {
# Retrieve the apps dependencies of the app # Retrieve the apps dependencies of the app
local apps_dependencies=$(ynh_app_setting_get --app=$app --key=apps_dependencies) local apps_dependencies=$(ynh_app_setting_get --app=$app --key=apps_dependencies)
ynh_app_setting_delete --app=$app --key=apps_dependencies ynh_app_setting_delete --app=$app --key=apps_dependencies
if [ ! -z "$apps_dependencies" ]; then if [ ! -z "$apps_dependencies" ]
# Split the list of apps dependencies in an array then
local apps_dependencies_list=($(echo $apps_dependencies | tr ", " "\n")) # Split the list of apps dependencies in an array
local apps_dependencies_list=($(echo $apps_dependencies | tr ", " "\n"))
# For each apps dependencies
for one_app in "${apps_dependencies_list[@]}"
do
# Retrieve the list of installed apps
local installed_apps_list=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_by=""
local installed_app_required_by=""
# For each apps dependencies # For each other installed app
for one_app in "${apps_dependencies_list[@]}"; do for one_installed_app in $installed_apps_list
# Retrieve the list of installed apps do
local installed_apps_list=$(yunohost app list --output-as json --quiet | jq -r .apps[].id) # Retrieve the other apps dependencies
local required_by="" one_installed_apps_dependencies=$(ynh_app_setting_get --app=$one_installed_app --key=apps_dependencies)
local installed_app_required_by="" if [ ! -z "$one_installed_apps_dependencies" ]
then
one_installed_apps_dependencies_list=($(echo $one_installed_apps_dependencies | tr ", " "\n"))
# For each other installed app # For each dependency of the other apps
for one_installed_app in $installed_apps_list; do for one_installed_app_dependency in "${one_installed_apps_dependencies_list[@]}"
# Retrieve the other apps dependencies do
one_installed_apps_dependencies=$(ynh_app_setting_get --app=$one_installed_app --key=apps_dependencies) if [[ $one_installed_app_dependency == $one_app ]]; then
if [ ! -z "$one_installed_apps_dependencies" ]; then required_by="$required_by $one_installed_app"
one_installed_apps_dependencies_list=($(echo $one_installed_apps_dependencies | tr ", " "\n")) fi
done
fi
done
# For each dependency of the other apps # If $one_app is no more required
for one_installed_app_dependency in "${one_installed_apps_dependencies_list[@]}"; do if [[ -z "$required_by" ]]
if [[ $one_installed_app_dependency == $one_app ]]; then then
required_by="$required_by $one_installed_app" # Remove $one_app
fi ynh_print_info --message="Removing of $one_app"
done yunohost app remove $one_app --purge
fi else
done ynh_print_info --message="$one_app was not removed because it's still required by${required_by}"
fi
# If $one_app is no more required done
if [[ -z "$required_by" ]]; then fi
# Remove $one_app
ynh_print_info --message="Removing of $one_app"
yunohost app remove $one_app --purge
else
ynh_print_info --message="$one_app was not removed because it's still required by${required_by}"
fi
done
fi
} }
# Spawn a Bash shell with the app environment loaded # Spawn a Bash shell with the app environment loaded
@ -117,83 +126,90 @@ ynh_remove_apps() {
# from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting). # from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting).
# If the app relies on a specific PHP version, then `php` will be aliased that version. The PHP command will also be appended with the `phpflags` settings. # If the app relies on a specific PHP version, then `php` will be aliased that version. The PHP command will also be appended with the `phpflags` settings.
ynh_spawn_app_shell() { ynh_spawn_app_shell() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=a local legacy_args=a
local -A args_array=([a]=app=) local -A args_array=([a]=app=)
local app local app
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# Force Bash to be used to run this helper # Force Bash to be used to run this helper
if [[ ! $0 =~ \/?bash$ ]]; then if [[ ! $0 =~ \/?bash$ ]]
ynh_print_err --message="Please use Bash as shell" then
exit 1 ynh_print_err --message="Please use Bash as shell"
fi exit 1
fi
# Make sure the app is installed # Make sure the app is installed
local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id)) local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id))
if [[ " ${installed_apps_list[*]} " != *" ${app} "* ]]; then if [[ " ${installed_apps_list[*]} " != *" ${app} "* ]]
ynh_print_err --message="$app is not in the apps list" then
exit 1 ynh_print_err --message="$app is not in the apps list"
fi exit 1
fi
# Make sure the app has its own user # Make sure the app has its own user
if ! id -u "$app" &> /dev/null; then if ! id -u "$app" &>/dev/null; then
ynh_print_err --message="There is no \"$app\" system user" ynh_print_err --message="There is no \"$app\" system user"
exit 1 exit 1
fi fi
# Make sure the app has an install_dir setting # Make sure the app has an install_dir setting
local install_dir=$(ynh_app_setting_get --app=$app --key=install_dir) local install_dir=$(ynh_app_setting_get --app=$app --key=install_dir)
if [ -z "$install_dir" ]; then if [ -z "$install_dir" ]
ynh_print_err --message="$app has no install_dir setting (does it use packaging format >=2?)" then
exit 1 ynh_print_err --message="$app has no install_dir setting (does it use packaging format >=2?)"
fi exit 1
fi
# Load the app's service name, or default to $app # Load the app's service name, or default to $app
local service=$(ynh_app_setting_get --app=$app --key=service) local service=$(ynh_app_setting_get --app=$app --key=service)
[ -z "$service" ] && service=$app [ -z "$service" ] && service=$app;
# Export HOME variable # Export HOME variable
export HOME=$install_dir export HOME=$install_dir;
# Load the Environment variables from the app's service # Load the Environment variables from the app's service
local env_var=$(systemctl show $service.service -p "Environment" --value) local env_var=$(systemctl show $service.service -p "Environment" --value)
[ -n "$env_var" ] && export $env_var [ -n "$env_var" ] && export $env_var;
# Force `php` to its intended version # Force `php` to its intended version
# We use `eval`+`export` since `alias` is not propagated to subshells, even with `export` # We use `eval`+`export` since `alias` is not propagated to subshells, even with `export`
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
local phpflags=$(ynh_app_setting_get --app=$app --key=phpflags) local phpflags=$(ynh_app_setting_get --app=$app --key=phpflags)
if [ -n "$phpversion" ]; then if [ -n "$phpversion" ]
eval "php() { php${phpversion} ${phpflags} \"\$@\"; }" then
export -f php eval "php() { php${phpversion} ${phpflags} \"\$@\"; }"
fi export -f php
fi
# Source the EnvironmentFiles from the app's service # Source the EnvironmentFiles from the app's service
local env_files=($(systemctl show $service.service -p "EnvironmentFiles" --value)) local env_files=($(systemctl show $service.service -p "EnvironmentFiles" --value))
if [ ${#env_files[*]} -gt 0 ]; then if [ ${#env_files[*]} -gt 0 ]
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`. then
set -a # set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
for file in ${env_files[*]}; do set -a
[[ $file = /* ]] && source $file for file in ${env_files[*]}
done do
set +a [[ $file = /* ]] && source $file
fi done
set +a
fi
# Activate the Python environment, if it exists # Activate the Python environment, if it exists
if [ -f $install_dir/venv/bin/activate ]; then if [ -f $install_dir/venv/bin/activate ]
# set -/+a enables and disables new variables being automatically exported. Needed when using `source`. then
set -a # set -/+a enables and disables new variables being automatically exported. Needed when using `source`.
source $install_dir/venv/bin/activate set -a
set +a source $install_dir/venv/bin/activate
fi set +a
fi
# cd into the WorkingDirectory set in the service, or default to the install_dir # cd into the WorkingDirectory set in the service, or default to the install_dir
local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value) local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value)
[ -z $env_dir ] && env_dir=$install_dir [ -z $env_dir ] && env_dir=$install_dir;
cd $env_dir cd $env_dir
# Spawn the app shell # Spawn the app shell
su -s /bin/bash $app su -s /bin/bash $app
} }

View file

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

View file

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

View file

@ -6,11 +6,11 @@ _ynh_app_config_get_one() {
local bind="$3" local bind="$3"
local getter="get__${short_setting}" local getter="get__${short_setting}"
# Get value from getter if exists # Get value from getter if exists
if type -t $getter 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
old[$short_setting]="$($getter)" old[$short_setting]="$($getter)"
formats[${short_setting}]="yaml" formats[${short_setting}]="yaml"
elif [[ "$bind" == *"("* ]] && type -t "get__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then 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)" old[$short_setting]="$("get__${bind%%(*}" $short_setting $type $bind)"
formats[${short_setting}]="yaml" formats[${short_setting}]="yaml"
@ -22,7 +22,7 @@ _ynh_app_config_get_one() {
if [[ "$bind" == "settings" ]]; then if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings" ynh_die --message="File '${short_setting}' can't be stored in settings"
fi fi
old[$short_setting]="$(ls "$bind" 2> /dev/null || echo YNH_NULL)" old[$short_setting]="$(ls "$(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)" 2>/dev/null || echo YNH_NULL)"
file_hash[$short_setting]="true" file_hash[$short_setting]="true"
# Get multiline text from settings or from a full file # Get multiline text from settings or from a full file
@ -32,7 +32,7 @@ _ynh_app_config_get_one() {
elif [[ "$bind" == *":"* ]]; then elif [[ "$bind" == *":"* ]]; then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter" ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else else
old[$short_setting]="$(cat "$bind" 2> /dev/null || echo YNH_NULL)" old[$short_setting]="$(cat $(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
fi fi
# Get value from a kind of key/value file # Get value from a kind of key/value file
@ -47,7 +47,7 @@ _ynh_app_config_get_one() {
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)" bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)" bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi fi
local bind_file="$(echo "$bind" | cut -d: -f2)" local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")" old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
fi fi
@ -59,10 +59,10 @@ _ynh_app_config_apply_one() {
local type="${types[$short_setting]}" local type="${types[$short_setting]}"
if [ "${changed[$short_setting]}" == "true" ]; then if [ "${changed[$short_setting]}" == "true" ]; then
# Apply setter if exists # Apply setter if exists
if type -t $setter 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
$setter $setter
elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"set__${bind%%(*}" $short_setting $type $bind "set__${bind%%(*}" $short_setting $type $bind
elif [[ "$bind" == "null" ]]; then elif [[ "$bind" == "null" ]]; then
@ -73,7 +73,7 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == "settings" ]]; then if [[ "$bind" == "settings" ]]; then
ynh_die --message="File '${short_setting}' can't be stored in settings" ynh_die --message="File '${short_setting}' can't be stored in settings"
fi fi
local bind_file="$bind" local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
if [[ "${!short_setting}" == "" ]]; then if [[ "${!short_setting}" == "" ]]; then
ynh_backup_if_checksum_is_different --file="$bind_file" ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_secure_remove --file="$bind_file" ynh_secure_remove --file="$bind_file"
@ -98,9 +98,9 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == *":"* ]]; then if [[ "$bind" == *":"* ]]; then
ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter" ynh_die --message="For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
fi fi
local bind_file="$bind" local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file" ynh_backup_if_checksum_is_different --file="$bind_file"
echo "${!short_setting}" > "$bind_file" echo "${!short_setting}" >"$bind_file"
ynh_store_file_checksum --file="$bind_file" --update_only ynh_store_file_checksum --file="$bind_file" --update_only
ynh_print_info --message="File '$bind_file' overwritten with the content provided in question '${short_setting}'" ynh_print_info --message="File '$bind_file' overwritten with the content provided in question '${short_setting}'"
@ -113,7 +113,7 @@ _ynh_app_config_apply_one() {
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)" bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi fi
bind_key_=${bind_key_:-$short_setting} bind_key_=${bind_key_:-$short_setting}
local bind_file="$(echo "$bind" | cut -d: -f2)" local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s@__FINALPATH__@${final_path:-}@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different --file="$bind_file" ynh_backup_if_checksum_is_different --file="$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}" ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
@ -126,17 +126,69 @@ _ynh_app_config_apply_one() {
fi fi
fi fi
} }
_ynh_app_config_get() { _ynh_app_config_get() {
for line in $YNH_APP_CONFIG_PANEL_OPTIONS_TYPES_AND_BINDS; do # From settings
local lines
lines=$(
python3 <<EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
bind_panel = panel.get('bind')
for section_name, section in panel.items():
if not isinstance(section, dict): continue
bind_section = section.get('bind')
if not bind_section:
bind_section = bind_panel
elif bind_section[-1] == ":" and bind_panel and ":" in bind_panel:
regex, bind_panel_file = bind_panel.split(":")
if ">" in bind_section:
bind_section = bind_section + bind_panel_file
else:
bind_section = regex + bind_section + bind_panel_file
for name, param in section.items():
if not isinstance(param, dict):
continue
bind = param.get('bind')
if not bind:
if bind_section:
bind = bind_section
else:
bind = 'settings'
elif bind[-1] == ":" and bind_section and ":" in bind_section:
regex, bind_file = bind_section.split(":")
if ">" in bind:
bind = bind + bind_file
else:
bind = regex + bind + bind_file
if bind == "settings" and param.get('type', 'string') == 'file':
bind = 'null'
print('|'.join([
name,
param.get('type', 'string'),
bind
]))
EOL
)
for line in $lines; do
# Split line into short_setting, type and bind # Split line into short_setting, type and bind
IFS='|' read short_setting type bind <<< "$line" IFS='|' read short_setting type bind <<<"$line"
binds[${short_setting}]="$bind" binds[${short_setting}]="$bind"
types[${short_setting}]="$type" types[${short_setting}]="$type"
file_hash[${short_setting}]="" file_hash[${short_setting}]=""
formats[${short_setting}]="" formats[${short_setting}]=""
ynh_app_config_get_one $short_setting $type $bind ynh_app_config_get_one $short_setting $type $bind
done done
} }
_ynh_app_config_apply() { _ynh_app_config_apply() {
@ -206,9 +258,9 @@ _ynh_app_config_validate() {
for short_setting in "${!old[@]}"; do for short_setting in "${!old[@]}"; do
[[ "${changed[$short_setting]}" == "false" ]] && continue [[ "${changed[$short_setting]}" == "false" ]] && continue
local result="" local result=""
if type -t validate__$short_setting | grep -q '^function$' 2> /dev/null; then if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
result="$(validate__$short_setting)" result="$(validate__$short_setting)"
elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"validate__${bind%%(*}" $short_setting "validate__${bind%%(*}" $short_setting
fi fi
if [ -n "$result" ]; then if [ -n "$result" ]; then
@ -263,7 +315,7 @@ ynh_app_config_apply() {
ynh_app_action_run() { ynh_app_action_run() {
local runner="run__$1" local runner="run__$1"
# Get value from getter if exists # Get value from getter if exists
if type -t "$runner" 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t "$runner" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
$runner $runner
#ynh_return "result:" #ynh_return "result:"
#ynh_return "$(echo "${result}" | sed 's/^/ /g')" #ynh_return "$(echo "${result}" | sed 's/^/ /g')"
@ -281,23 +333,22 @@ ynh_app_config_run() {
declare -Ag formats=() declare -Ag formats=()
case $1 in case $1 in
show) show)
ynh_app_config_get ynh_app_config_get
ynh_app_config_show ynh_app_config_show
;; ;;
apply) apply)
max_progression=4 max_progression=4
ynh_script_progression --message="Reading config panel description and current configuration..." ynh_script_progression --message="Reading config panel description and current configuration..."
ynh_app_config_get ynh_app_config_get
ynh_app_config_validate ynh_app_config_validate
ynh_script_progression --message="Applying the new configuration..." ynh_script_progression --message="Applying the new configuration..."
ynh_app_config_apply ynh_app_config_apply
ynh_script_progression --message="Configuration of $app completed" --last ynh_script_progression --message="Configuration of $app completed" --last
;; ;;
*) *)
ynh_app_action_run $1 ynh_app_action_run $1
;;
esac esac
} }

View file

@ -82,7 +82,7 @@ port = __PORTS__
filter = __APP__ filter = __APP__
logpath = __LOGPATH__ logpath = __LOGPATH__
maxretry = __MAX_RETRY__ maxretry = __MAX_RETRY__
" > "$YNH_APP_BASEDIR/conf/f2b_jail.conf" " >"$YNH_APP_BASEDIR/conf/f2b_jail.conf"
echo " echo "
[INCLUDES] [INCLUDES]
@ -90,7 +90,7 @@ before = common.conf
[Definition] [Definition]
failregex = __FAILREGEX__ failregex = __FAILREGEX__
ignoreregex = ignoreregex =
" > "$YNH_APP_BASEDIR/conf/f2b_filter.conf" " >"$YNH_APP_BASEDIR/conf/f2b_filter.conf"
fi fi
ynh_add_config --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf" ynh_add_config --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
@ -113,7 +113,7 @@ ignoreregex =
chown -R "$app:$app" "/var/log/$app" chown -R "$app:$app" "/var/log/$app"
chmod -R u=rwX,g=rX,o= "/var/log/$app" chmod -R u=rwX,g=rX,o= "/var/log/$app"
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) fail2ban.service" --log_path=systemd
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")" local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
if [[ -n "$fail2ban_error" ]]; then if [[ -n "$fail2ban_error" ]]; then

View file

@ -20,7 +20,7 @@
# | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function # | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function
# #
# This helper need an array, named "args_array" with all the arguments used by the helper # This helper need an array, named "args_array" with all the arguments used by the helper
# that want to use ynh_handle_getopts_args # that want to use ynh_handle_getopts_args
# Be carreful, this array has to be an associative array, as the following example: # Be carreful, this array has to be an associative array, as the following example:
# local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 ) # local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
# Let's explain this array: # Let's explain this array:
@ -180,7 +180,7 @@ ynh_handle_getopts_args() {
# 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 set -x
echo "! Helper used in legacy mode !" > /dev/null echo "! Helper used in legacy mode !" >/dev/null
set +x set +x
local i local i
for i in $(seq 0 $((${#arguments[@]} - 1))); do for i in $(seq 0 $((${#arguments[@]} - 1))); do

View file

@ -1,11 +1,11 @@
#!/bin/bash #!/bin/bash
ynh_go_try_bash_extension() { ynh_go_try_bash_extension() {
if [ -x src/configure ]; then if [ -x src/configure ]; then
src/configure && make -C src || { src/configure && make -C src || {
ynh_print_info --message="Optional bash extension failed to build, but things will still work normally." ynh_print_info --message="Optional bash extension failed to build, but things will still work normally."
} }
fi fi
} }
goenv_install_dir="/opt/goenv" goenv_install_dir="/opt/goenv"
@ -51,7 +51,7 @@ export GOENV_ROOT="$goenv_install_dir"
# usage: ynh_use_go # usage: ynh_use_go
# #
# Requires YunoHost version 3.2.2 or higher. # Requires YunoHost version 3.2.2 or higher.
ynh_use_go() { ynh_use_go () {
go_version=$(ynh_app_setting_get --app=$app --key=go_version) go_version=$(ynh_app_setting_get --app=$app --key=go_version)
# Get the absolute path of this version of Go # Get the absolute path of this version of Go
@ -73,7 +73,7 @@ ynh_use_go() {
# Sets the local application-specific Go version # Sets the local application-specific Go version
pushd $install_dir pushd $install_dir
$goenv_install_dir/bin/goenv local $go_version $goenv_install_dir/bin/goenv local $go_version
popd popd
} }
@ -93,10 +93,10 @@ ynh_use_go() {
# | arg: -v, --go_version= - Version of go to install. # | arg: -v, --go_version= - Version of go to install.
# #
# Requires YunoHost version 3.2.2 or higher. # Requires YunoHost version 3.2.2 or higher.
ynh_install_go() { ynh_install_go () {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=v local legacy_args=v
local -A args_array=([v]=go_version=) local -A args_array=( [v]=go_version= )
local go_version local go_version
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -113,34 +113,34 @@ ynh_install_go() {
# Install or update goenv # Install or update goenv
mkdir -p $goenv_install_dir mkdir -p $goenv_install_dir
pushd "$goenv_install_dir" pushd "$goenv_install_dir"
if ! [ -x "$goenv_install_dir/bin/goenv" ]; then if ! [ -x "$goenv_install_dir/bin/goenv" ]; then
ynh_print_info --message="Downloading goenv..." ynh_print_info --message="Downloading goenv..."
git init -q git init -q
git remote add origin https://github.com/syndbg/goenv.git git remote add origin https://github.com/syndbg/goenv.git
else else
ynh_print_info --message="Updating goenv..." ynh_print_info --message="Updating goenv..."
fi fi
git fetch -q --tags --prune origin git fetch -q --tags --prune origin
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
git checkout -q "$git_latest_tag" git checkout -q "$git_latest_tag"
ynh_go_try_bash_extension ynh_go_try_bash_extension
goenv=$goenv_install_dir/bin/goenv goenv=$goenv_install_dir/bin/goenv
popd popd
# Install or update xxenv-latest # Install or update xxenv-latest
goenv_latest_dir="$goenv_install_dir/plugins/xxenv-latest" goenv_latest_dir="$goenv_install_dir/plugins/xxenv-latest"
mkdir -p "$goenv_latest_dir" mkdir -p "$goenv_latest_dir"
pushd "$goenv_latest_dir" pushd "$goenv_latest_dir"
if ! [ -x "$goenv_latest_dir/bin/goenv-latest" ]; then if ! [ -x "$goenv_latest_dir/bin/goenv-latest" ]; then
ynh_print_info --message="Downloading xxenv-latest..." ynh_print_info --message="Downloading xxenv-latest..."
git init -q git init -q
git remote add origin https://github.com/momo-lab/xxenv-latest.git git remote add origin https://github.com/momo-lab/xxenv-latest.git
else else
ynh_print_info --message="Updating xxenv-latest..." ynh_print_info --message="Updating xxenv-latest..."
fi fi
git fetch -q --tags --prune origin git fetch -q --tags --prune origin
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
git checkout -q "$git_latest_tag" git checkout -q "$git_latest_tag"
popd popd
# Enable caching # Enable caching
@ -167,7 +167,7 @@ ynh_install_go() {
ynh_cleanup_go ynh_cleanup_go
# Set environment for Go users # Set environment for Go users
echo "#goenv echo "#goenv
export GOENV_ROOT=$goenv_install_dir export GOENV_ROOT=$goenv_install_dir
export PATH=\"$goenv_install_dir/bin:$PATH\" export PATH=\"$goenv_install_dir/bin:$PATH\"
eval \"\$(goenv init -)\" eval \"\$(goenv init -)\"
@ -182,7 +182,7 @@ eval \"\$(goenv init -)\"
# This helper will also cleanup Go versions # This helper will also cleanup Go versions
# #
# usage: ynh_remove_go # usage: ynh_remove_go
ynh_remove_go() { ynh_remove_go () {
local go_version=$(ynh_app_setting_get --app="$app" --key="go_version") local go_version=$(ynh_app_setting_get --app="$app" --key="go_version")
# Load goenv path in PATH # Load goenv path in PATH
@ -205,29 +205,34 @@ ynh_remove_go() {
# If no app uses Go, goenv will be also removed. # If no app uses Go, goenv will be also removed.
# #
# usage: ynh_cleanup_go # usage: ynh_cleanup_go
ynh_cleanup_go() { ynh_cleanup_go () {
# List required Go versions # List required Go versions
local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id) local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_go_versions="" local required_go_versions=""
for installed_app in $installed_apps; do for installed_app in $installed_apps
do
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version") local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
if [[ $installed_app_go_version ]]; then if [[ $installed_app_go_version ]]
then
required_go_versions="${installed_app_go_version}\n${required_go_versions}" required_go_versions="${installed_app_go_version}\n${required_go_versions}"
fi fi
done done
# Remove no more needed Go versions # Remove no more needed Go versions
local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/') local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/')
for installed_go_version in $installed_go_versions; do for installed_go_version in $installed_go_versions
if ! $(echo ${required_go_versions} | grep "${installed_go_version}" 1> /dev/null 2>&1); then do
if ! `echo ${required_go_versions} | grep "${installed_go_version}" 1>/dev/null 2>&1`
then
ynh_print_info --message="Removing of Go-$installed_go_version" ynh_print_info --message="Removing of Go-$installed_go_version"
$goenv_install_dir/bin/goenv uninstall --force "$installed_go_version" $goenv_install_dir/bin/goenv uninstall --force "$installed_go_version"
fi fi
done done
# If none Go version is required # If none Go version is required
if [[ ! $required_go_versions ]]; then if [[ ! $required_go_versions ]]
then
# Remove goenv environment configuration # Remove goenv environment configuration
ynh_print_info --message="Removing of goenv" ynh_print_info --message="Removing of goenv"
ynh_secure_remove --file="$goenv_install_dir" ynh_secure_remove --file="$goenv_install_dir"

View file

@ -93,7 +93,8 @@ ynh_exec_err() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes, # Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ... # (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space # we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
ynh_print_err --message="$(eval $@)" ynh_print_err --message="$(eval $@)"
else else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -113,7 +114,8 @@ ynh_exec_warn() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes, # Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ... # (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space # we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
ynh_print_warn --message="$(eval $@)" ynh_print_warn --message="$(eval $@)"
else else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -133,7 +135,8 @@ ynh_exec_warn_less() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes, # Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ... # (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space # we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
eval $@ 2>&1 eval $@ 2>&1
else else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -153,7 +156,8 @@ ynh_exec_quiet() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes, # Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ... # (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space # we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
eval $@ > /dev/null eval $@ > /dev/null
else else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -173,7 +177,8 @@ ynh_exec_fully_quiet() {
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes, # Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
# (because in the past eval was used) ... # (because in the past eval was used) ...
# we detect this by checking that there's no 2nd arg, and $1 contains a space # we detect this by checking that there's no 2nd arg, and $1 contains a space
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]; then if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
then
eval $@ > /dev/null 2>&1 eval $@ > /dev/null 2>&1
else else
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
@ -194,7 +199,7 @@ ynh_exec_and_print_stderr_only_if_error() {
rc=0 rc=0
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
"$@" 2> "$logfile" || rc="$?" "$@" 2> "$logfile" || rc="$?"
if ((rc != 0)); then if (( rc != 0 )); then
ynh_exec_warn cat "$logfile" ynh_exec_warn cat "$logfile"
ynh_secure_remove "$logfile" ynh_secure_remove "$logfile"
return "$rc" return "$rc"
@ -211,7 +216,7 @@ ynh_exec_and_print_stderr_only_if_error() {
# #
# 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
} }
# Restore the logging after ynh_print_OFF # Restore the logging after ynh_print_OFF
@ -224,7 +229,7 @@ ynh_print_OFF() {
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
@ -266,9 +271,9 @@ ynh_script_progression() {
# Always activate time when running inside CI tests # Always activate time when running inside CI tests
if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then if [ ${PACKAGE_CHECK_EXEC:-0} -eq 1 ]; then
time=${time:-1} time=${time:-1}
else else
time=${time:-0} time=${time:-0}
fi fi
last=${last:-0} last=${last:-0}
@ -293,8 +298,8 @@ ynh_script_progression() {
local weight_values=$(($(echo "$weight_valuesA" "$weight_valuesB" | grep -v -E '^\s*$' | tr '\n' '+' | sed 's/+$/+0/g'))) 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
@ -324,7 +329,7 @@ ynh_script_progression() {
local print_exec_time="" local print_exec_time=""
if [ $time -eq 1 ] && [ "$exec_time" -gt 10 ]; then if [ $time -eq 1 ] && [ "$exec_time" -gt 10 ]; then
print_exec_time=" [$(bc <<< "scale=1; $exec_time / 60") minutes]" print_exec_time=" [$(bc <<< "scale=1; $exec_time / 60" ) minutes]"
fi fi
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}" ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
@ -338,5 +343,5 @@ ynh_script_progression() {
# #
# 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"
} }

View file

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

View file

@ -6,92 +6,100 @@
# example: ynh_mongo_exec --command="db.getMongo().getDBNames().indexOf(\"wekan\")" # example: ynh_mongo_exec --command="db.getMongo().getDBNames().indexOf(\"wekan\")"
# #
# usage: ynh_mongo_exec [--user=user] [--password=password] [--authenticationdatabase=authenticationdatabase] [--database=database] [--host=host] [--port=port] --command="command" [--eval] # usage: ynh_mongo_exec [--user=user] [--password=password] [--authenticationdatabase=authenticationdatabase] [--database=database] [--host=host] [--port=port] --command="command" [--eval]
# | arg: -u, --user= - The user name to connect as # | arg: -u, --user= - The user name to connect as
# | arg: -p, --password= - The user password # | arg: -p, --password= - The user password
# | arg: -d, --authenticationdatabase= - The authenticationdatabase to connect to # | arg: -d, --authenticationdatabase= - The authenticationdatabase to connect to
# | arg: -d, --database= - The database to connect to # | arg: -d, --database= - The database to connect to
# | arg: -h, --host= - The host to connect to # | arg: -h, --host= - The host to connect to
# | arg: -P, --port= - The port to connect to # | arg: -P, --port= - The port to connect to
# | arg: -c, --command= - The command to evaluate # | arg: -c, --command= - The command to evaluate
# | arg: -e, --eval - Evaluate instead of execute the command. # | arg: -e, --eval - Evaluate instead of execute the command.
# #
# #
ynh_mongo_exec() { ynh_mongo_exec() {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=upadhPce local legacy_args=upadhPce
local -A args_array=([u]=user= [p]=password= [a]=authenticationdatabase= [d]=database= [h]=host= [P]=port= [c]=command= [e]=eval) local -A args_array=( [u]=user= [p]=password= [a]=authenticationdatabase= [d]=database= [h]=host= [P]=port= [c]=command= [e]=eval )
local user local user
local password local password
local authenticationdatabase local authenticationdatabase
local database local database
local host local host
local port local port
local command local command
local eval local eval
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
user="${user:-}" user="${user:-}"
password="${password:-}" password="${password:-}"
authenticationdatabase="${authenticationdatabase:-}" authenticationdatabase="${authenticationdatabase:-}"
database="${database:-}" database="${database:-}"
host="${host:-}" host="${host:-}"
port="${port:-}" port="${port:-}"
eval=${eval:-0} eval=${eval:-0}
# If user is provided # If user is provided
if [ -n "$user" ]; then if [ -n "$user" ]
user="--username=$user" then
user="--username=$user"
# If password is provided # If password is provided
if [ -n "$password" ]; then if [ -n "$password" ]
password="--password=$password" then
fi password="--password=$password"
fi
# If authenticationdatabase is provided # If authenticationdatabase is provided
if [ -n "$authenticationdatabase" ]; then if [ -n "$authenticationdatabase" ]
authenticationdatabase="--authenticationDatabase=$authenticationdatabase" then
else authenticationdatabase="--authenticationDatabase=$authenticationdatabase"
authenticationdatabase="--authenticationDatabase=admin" else
fi authenticationdatabase="--authenticationDatabase=admin"
else fi
password="" else
authenticationdatabase="" password=""
fi authenticationdatabase=""
fi
# If host is provided # If host is provided
if [ -n "$host" ]; then if [ -n "$host" ]
host="--host=$host" then
fi host="--host=$host"
fi
# If port is provided # If port is provided
if [ -n "$port" ]; then if [ -n "$port" ]
port="--port=$port" then
fi port="--port=$port"
fi
# If eval is not provided # If eval is not provided
if [ $eval -eq 0 ]; then if [ $eval -eq 0 ]
# If database is provided then
if [ -n "$database" ]; then # If database is provided
database="use $database" if [ -n "$database" ]
else then
database="" database="use $database"
fi else
database=""
fi
mongosh --quiet --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port << EOF mongosh --quiet --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port <<EOF
$database $database
${command} ${command}
quit() quit()
EOF EOF
else else
# If database is provided # If database is provided
if [ -n "$database" ]; then if [ -n "$database" ]
database="$database" then
else database="$database"
database="" else
fi database=""
fi
mongosh --quiet $database --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port --eval="$command" mongosh --quiet $database --username $user --password $password --authenticationDatabase $authenticationdatabase --host $host --port $port --eval="$command"
fi fi
} }
# Drop a database # Drop a database
@ -102,18 +110,18 @@ EOF
# consider using ynh_mongo_remove_db instead. # consider using ynh_mongo_remove_db instead.
# #
# usage: ynh_mongo_drop_db --database=database # usage: ynh_mongo_drop_db --database=database
# | arg: -d, --database= - The database name to drop # | arg: -d, --database= - The database name to drop
# #
# #
ynh_mongo_drop_db() { ynh_mongo_drop_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 "$@"
ynh_mongo_exec --database="$database" --command='db.runCommand({dropDatabase: 1})' ynh_mongo_exec --database="$database" --command='db.runCommand({dropDatabase: 1})'
} }
# Dump a database # Dump a database
@ -121,19 +129,19 @@ ynh_mongo_drop_db() {
# example: ynh_mongo_dump_db --database=wekan > ./dump.bson # example: ynh_mongo_dump_db --database=wekan > ./dump.bson
# #
# usage: ynh_mongo_dump_db --database=database # usage: ynh_mongo_dump_db --database=database
# | arg: -d, --database= - The database name to dump # | arg: -d, --database= - The database name to dump
# | ret: the mongodump output # | ret: the mongodump output
# #
# #
ynh_mongo_dump_db() { ynh_mongo_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 "$@"
mongodump --quiet --db="$database" --archive mongodump --quiet --db="$database" --archive
} }
# Create a user # Create a user
@ -141,48 +149,49 @@ ynh_mongo_dump_db() {
# [internal] # [internal]
# #
# usage: ynh_mongo_create_user --db_user=user --db_pwd=pwd --db_name=name # usage: ynh_mongo_create_user --db_user=user --db_pwd=pwd --db_name=name
# | arg: -u, --db_user= - The user name to create # | arg: -u, --db_user= - The user name to create
# | arg: -p, --db_pwd= - The password to identify user by # | arg: -p, --db_pwd= - The password to identify user by
# | arg: -n, --db_name= - Name of the database to grant privilegies # | arg: -n, --db_name= - Name of the database to grant privilegies
# #
# #
ynh_mongo_create_user() { ynh_mongo_create_user() {
# 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
local db_pwd local db_pwd
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# Create the user and set the user as admin of the db # Create the user and set the user as admin of the db
ynh_mongo_exec --database="$db_name" --command='db.createUser( { user: "'${db_user}'", pwd: "'${db_pwd}'", roles: [ { role: "readWrite", db: "'${db_name}'" } ] } );' ynh_mongo_exec --database="$db_name" --command='db.createUser( { user: "'${db_user}'", pwd: "'${db_pwd}'", roles: [ { role: "readWrite", db: "'${db_name}'" } ] } );'
# Add clustermonitoring rights # Add clustermonitoring rights
ynh_mongo_exec --database="$db_name" --command='db.grantRolesToUser("'${db_user}'",[{ role: "clusterMonitor", db: "admin" }]);' ynh_mongo_exec --database="$db_name" --command='db.grantRolesToUser("'${db_user}'",[{ role: "clusterMonitor", db: "admin" }]);'
} }
# Check if a mongo database exists # Check if a mongo database exists
# #
# usage: ynh_mongo_database_exists --database=database # usage: ynh_mongo_database_exists --database=database
# | arg: -d, --database= - The database for which to check existence # | arg: -d, --database= - The database for which to check existence
# | exit: Return 1 if the database doesn't exist, 0 otherwise # | exit: Return 1 if the database doesn't exist, 0 otherwise
# #
# #
ynh_mongo_database_exists() { ynh_mongo_database_exists() {
# 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 "$@"
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")' --eval) -lt 0 ]; then if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")' --eval) -lt 0 ]
return 1 then
else return 1
return 0 else
fi return 0
fi
} }
# Restore a database # Restore a database
@ -190,18 +199,18 @@ ynh_mongo_database_exists() {
# example: ynh_mongo_restore_db --database=wekan < ./dump.bson # example: ynh_mongo_restore_db --database=wekan < ./dump.bson
# #
# usage: ynh_mongo_restore_db --database=database # usage: ynh_mongo_restore_db --database=database
# | arg: -d, --database= - The database name to restore # | arg: -d, --database= - The database name to restore
# #
# #
ynh_mongo_restore_db() { ynh_mongo_restore_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 "$@"
mongorestore --quiet --db="$database" --archive mongorestore --quiet --db="$database" --archive
} }
# Drop a user # Drop a user
@ -209,120 +218,120 @@ ynh_mongo_restore_db() {
# [internal] # [internal]
# #
# usage: ynh_mongo_drop_user --db_user=user --db_name=name # usage: ynh_mongo_drop_user --db_user=user --db_name=name
# | arg: -u, --db_user= - The user to drop # | arg: -u, --db_user= - The user to drop
# | arg: -n, --db_name= - Name of the database # | arg: -n, --db_name= - Name of the database
# #
# #
ynh_mongo_drop_user() { ynh_mongo_drop_user() {
# 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 -A 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 "$@"
ynh_mongo_exec --database="$db_name" --command='db.dropUser("'$db_user'", {w: "majority", wtimeout: 5000})' ynh_mongo_exec --database="$db_name" --command='db.dropUser("'$db_user'", {w: "majority", wtimeout: 5000})'
} }
# Create a database, an user and its password. Then store the password in the app's config # Create a database, an user and its password. Then store the password in the app's config
# #
# usage: ynh_mongo_setup_db --db_user=user --db_name=name [--db_pwd=pwd] # usage: ynh_mongo_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
# | arg: -u, --db_user= - Owner of the database # | arg: -u, --db_user= - Owner of the database
# | arg: -n, --db_name= - Name of the database # | arg: -n, --db_name= - Name of the database
# | 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 "mongopwd" into the app settings. # It will also be stored as "mongopwd" into the app settings.
# #
# #
ynh_mongo_setup_db() { ynh_mongo_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 local new_db_pwd=$(ynh_string_random) # Generate a random password
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd # 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}"
# Create the user and grant access to the database # Create the user and grant access to the database
ynh_mongo_create_user --db_user="$db_user" --db_pwd="$db_pwd" --db_name="$db_name" ynh_mongo_create_user --db_user="$db_user" --db_pwd="$db_pwd" --db_name="$db_name"
# Store the password in the app's config # Store the password in the app's config
ynh_app_setting_set --app=$app --key=db_pwd --value=$db_pwd ynh_app_setting_set --app=$app --key=db_pwd --value=$db_pwd
} }
# Remove a database if it exists, and the associated user # Remove a database if it exists, and the associated user
# #
# usage: ynh_mongo_remove_db --db_user=user --db_name=name # usage: ynh_mongo_remove_db --db_user=user --db_name=name
# | arg: -u, --db_user= - Owner of the database # | arg: -u, --db_user= - Owner of the database
# | arg: -n, --db_name= - Name of the database # | arg: -n, --db_name= - Name of the database
# #
# #
ynh_mongo_remove_db() { ynh_mongo_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 -A 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 "$@"
if ynh_mongo_database_exists --database=$db_name; then # Check if the database exists if ynh_mongo_database_exists --database=$db_name; then # Check if the database exists
ynh_mongo_drop_db --database=$db_name # Remove the database ynh_mongo_drop_db --database=$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 mongo user if it exists # Remove mongo user if it exists
ynh_mongo_drop_user --db_user=$db_user --db_name=$db_name ynh_mongo_drop_user --db_user=$db_user --db_name=$db_name
} }
# Install MongoDB and integrate MongoDB service in YunoHost # Install MongoDB and integrate MongoDB service in YunoHost
# #
# usage: ynh_install_mongo [--mongo_version=mongo_version] # usage: ynh_install_mongo [--mongo_version=mongo_version]
# | arg: -m, --mongo_version= - Version of MongoDB to install # | arg: -m, --mongo_version= - Version of MongoDB to install
# #
# #
ynh_install_mongo() { ynh_install_mongo() {
# 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]=mongo_version=) local -A args_array=([m]=mongo_version=)
local mongo_version local mongo_version
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
mongo_version="${mongo_version:-$YNH_MONGO_VERSION}" mongo_version="${mongo_version:-$YNH_MONGO_VERSION}"
ynh_print_info --message="Installing MongoDB Community Edition ..." ynh_print_info --message="Installing MongoDB Community Edition ..."
local mongo_debian_release=$(ynh_get_debian_release) local mongo_debian_release=$(ynh_get_debian_release)
if [[ "$(grep '^flags' /proc/cpuinfo | uniq)" != *"avx"* && "$mongo_version" != "4.4" ]]; then if [[ "$(grep '^flags' /proc/cpuinfo | uniq)" != *"avx"* && "$mongo_version" != "4.4" ]]; then
ynh_print_warn --message="Installing Mongo 4.4 as $mongo_version is not compatible with your cpu (see https://docs.mongodb.com/manual/administration/production-notes/#x86_64)." ynh_print_warn --message="Installing Mongo 4.4 as $mongo_version is not compatible with your cpu (see https://docs.mongodb.com/manual/administration/production-notes/#x86_64)."
mongo_version="4.4" mongo_version="4.4"
fi fi
if [[ "$mongo_version" == "4.4" ]]; then if [[ "$mongo_version" == "4.4" ]]; then
ynh_print_warn --message="Switched to buster install as Mongo 4.4 is not compatible with $mongo_debian_release." ynh_print_warn --message="Switched to buster install as Mongo 4.4 is not compatible with $mongo_debian_release."
mongo_debian_release=buster mongo_debian_release=buster
fi fi
ynh_install_extra_app_dependencies --repo="deb http://repo.mongodb.org/apt/debian $mongo_debian_release/mongodb-org/$mongo_version main" --package="mongodb-org mongodb-org-server mongodb-org-tools mongodb-mongosh" --key="https://www.mongodb.org/static/pgp/server-$mongo_version.asc" ynh_install_extra_app_dependencies --repo="deb http://repo.mongodb.org/apt/debian $mongo_debian_release/mongodb-org/$mongo_version main" --package="mongodb-org mongodb-org-server mongodb-org-tools mongodb-mongosh" --key="https://www.mongodb.org/static/pgp/server-$mongo_version.asc"
mongodb_servicename=mongod mongodb_servicename=mongod
# Make sure MongoDB is started and enabled # Make sure MongoDB is started and enabled
systemctl enable $mongodb_servicename --quiet systemctl enable $mongodb_servicename --quiet
systemctl daemon-reload --quiet systemctl daemon-reload --quiet
ynh_systemd_action --service_name=$mongodb_servicename --action=restart --line_match="aiting for connections" --log_path="/var/log/mongodb/$mongodb_servicename.log" ynh_systemd_action --service_name=$mongodb_servicename --action=restart --line_match="aiting for connections" --log_path="/var/log/mongodb/$mongodb_servicename.log"
# Integrate MongoDB service in YunoHost # Integrate MongoDB service in YunoHost
yunohost service add $mongodb_servicename --description="MongoDB daemon" --log="/var/log/mongodb/$mongodb_servicename.log" yunohost service add $mongodb_servicename --description="MongoDB daemon" --log="/var/log/mongodb/$mongodb_servicename.log"
# Store mongo_version into the config of this app # Store mongo_version into the config of this app
ynh_app_setting_set --app=$app --key=mongo_version --value=$mongo_version ynh_app_setting_set --app=$app --key=mongo_version --value=$mongo_version
} }
# Remove MongoDB # Remove MongoDB
@ -333,13 +342,14 @@ ynh_install_mongo() {
# #
# #
ynh_remove_mongo() { ynh_remove_mongo() {
# Only remove the mongodb service if it is not installed. # Only remove the mongodb service if it is not installed.
if ! ynh_package_is_installed --package="mongodb*"; then if ! ynh_package_is_installed --package="mongodb*"
ynh_print_info --message="Removing MongoDB service..." then
mongodb_servicename=mongod ynh_print_info --message="Removing MongoDB service..."
# Remove the mongodb service mongodb_servicename=mongod
yunohost service remove $mongodb_servicename # Remove the mongodb service
ynh_secure_remove --file="/var/lib/mongodb" yunohost service remove $mongodb_servicename
ynh_secure_remove --file="/var/log/mongodb" ynh_secure_remove --file="/var/lib/mongodb"
fi ynh_secure_remove --file="/var/log/mongodb"
fi
} }

View file

@ -47,7 +47,7 @@ ynh_mysql_execute_as_root() {
database="--database=$database" database="--database=$database"
fi fi
mysql -B "$database" <<< "$sql" mysql -B "$database" <<<"$sql"
} }
# Execute a command from a file as root user # Execute a command from a file as root user
@ -71,7 +71,7 @@ ynh_mysql_execute_file_as_root() {
database="--database=$database" database="--database=$database"
fi fi
mysql -B "$database" < "$file" mysql -B "$database" <"$file"
} }
# Create a database and grant optionnaly privilegies to a user # Create a database and grant optionnaly privilegies to a user
@ -227,6 +227,9 @@ ynh_mysql_setup_db() {
# 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}"
# Dirty patch for super-legacy apps
dpkg --list | grep -q "^ii mariadb-server" || { ynh_print_warn "Packager: you called ynh_mysql_setup_db without declaring a dependency to mariadb-server. Please add it to your apt dependencies !"; ynh_apt install mariadb-server; }
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd"
ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd
} }

View file

@ -79,7 +79,7 @@ ynh_validate_ip() {
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1 [ "$family" == "4" ] || [ "$family" == "6" ] || return 1
python3 /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 }

View file

@ -43,6 +43,7 @@ ynh_remove_nginx_config() {
ynh_systemd_action --service_name=nginx --action=reload ynh_systemd_action --service_name=nginx --action=reload
} }
# Regen the nginx config in a change url context # Regen the nginx config in a change url context
# #
# usage: ynh_change_url_nginx_config # usage: ynh_change_url_nginx_config
@ -52,7 +53,7 @@ ynh_change_url_nginx_config() {
# Make a backup of the original NGINX config file if manually modified # Make a backup of the original NGINX config file if manually modified
# (nb: this is possibly different from the same instruction called by # (nb: this is possibly different from the same instruction called by
# ynh_add_config inside ynh_add_nginx_config because the path may have # ynh_add_config inside ynh_add_nginx_config because the path may have
# changed if we're changing the domain too...) # changed if we're changing the domain too...)
local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
ynh_backup_if_checksum_is_different --file="$old_nginx_conf_path" ynh_backup_if_checksum_is_different --file="$old_nginx_conf_path"

View file

@ -174,7 +174,7 @@ ynh_permission_exists() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
yunohost user permission list "$app" --output-as json --quiet \ yunohost user permission list "$app" --output-as json --quiet \
| jq -e --arg perm "$app.$permission" '.permissions[$perm]' > /dev/null | jq -e --arg perm "$app.$permission" '.permissions[$perm]' >/dev/null
} }
# Redefine the url associated to a permission # Redefine the url associated to a permission
@ -342,7 +342,7 @@ ynh_permission_has_user() {
# Check both allowed and corresponding_users sections in the json # Check both allowed and corresponding_users sections in the json
for section in "allowed" "corresponding_users"; do for section in "allowed" "corresponding_users"; do
if yunohost user permission info "$app.$permission" --output-as json --quiet \ 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 | jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null; then
return 0 return 0
fi fi
done done

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
readonly YNH_DEFAULT_PHP_VERSION=7.4 readonly YNH_DEFAULT_PHP_VERSION=8.2
# Declare the actual PHP version to use. # Declare the actual PHP version to use.
# A packager willing to use another version of PHP can override the variable into its _common.sh. # A packager willing to use another version of PHP can override the variable into its _common.sh.
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
@ -11,19 +11,19 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
# #
# Case 1 (recommended) : your provided a snippet conf/extra_php-fpm.conf # Case 1 (recommended) : your provided a snippet conf/extra_php-fpm.conf
# #
# The actual PHP configuration will be automatically generated, # The actual PHP configuration will be automatically generated,
# and your extra_php-fpm.conf will be appended (typically contains PHP upload limits) # and your extra_php-fpm.conf will be appended (typically contains PHP upload limits)
# #
# The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf # The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf
# #
# Performance-related options in the PHP conf, such as : # Performance-related options in the PHP conf, such as :
# pm.max_children, pm.start_servers, pm.min_spare_servers pm.max_spare_servers # pm.max_children, pm.start_servers, pm.min_spare_servers pm.max_spare_servers
# are computed from two parameters called "usage" and "footprint" which can be set to low/medium/high. (cf details below) # are computed from two parameters called "usage" and "footprint" which can be set to low/medium/high. (cf details below)
# #
# If you wish to tweak those, please initialize the settings `fpm_usage` and `fpm_footprint` # If you wish to tweak those, please initialize the settings `fpm_usage` and `fpm_footprint`
# *prior* to calling this helper. Otherwise, "low" will be used as a default for both values. # *prior* to calling this helper. Otherwise, "low" will be used as a default for both values.
# #
# Otherwise, if you want the user to have control over these, we encourage to create a config panel # Otherwise, if you want the user to have control over these, we encourage to create a config panel
# (which should ultimately be standardized by the core ...) # (which should ultimately be standardized by the core ...)
# #
# Case 2 (deprecate) : you provided an entire conf/php-fpm.conf # Case 2 (deprecate) : you provided an entire conf/php-fpm.conf
@ -33,7 +33,7 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
# The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf # The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf
# #
# ---------------------- # ----------------------
# #
# fpm_footprint: Memory footprint of the service (low/medium/high). # fpm_footprint: Memory footprint of the service (low/medium/high).
# low - Less than 20 MB of RAM by pool. # low - Less than 20 MB of RAM by pool.
# medium - Between 20 MB and 40 MB of RAM by pool. # medium - Between 20 MB and 40 MB of RAM by pool.
@ -70,17 +70,14 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
ynh_add_fpm_config() { ynh_add_fpm_config() {
local _globalphpversion=${phpversion-:} local _globalphpversion=${phpversion-:}
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=vufpdg local legacy_args=vufg
local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service [g]=group=) local -A args_array=([v]=phpversion= [u]=usage= [f]=footprint= [g]=group=)
local group local group
local phpversion local phpversion
local usage local usage
local footprint local footprint
local package
local dedicated_service
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
package=${package:-}
group=${group:-} group=${group:-}
# The default behaviour is to use the template. # The default behaviour is to use the template.
@ -92,21 +89,21 @@ ynh_add_fpm_config() {
# If no usage provided, default to the value existing in setting ... or to low # If no usage provided, default to the value existing in setting ... or to low
local fpm_usage_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_usage) local fpm_usage_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_usage)
if [ -z "$usage" ]; then if [ -z "$usage" ]
then
usage=${fpm_usage_in_setting:-low} usage=${fpm_usage_in_setting:-low}
ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage
fi fi
# If no footprint provided, default to the value existing in setting ... or to low # If no footprint provided, default to the value existing in setting ... or to low
local fpm_footprint_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_footprint) local fpm_footprint_in_setting=$(ynh_app_setting_get --app=$app --key=fpm_footprint)
if [ -z "$footprint" ]; then if [ -z "$footprint" ]
then
footprint=${fpm_footprint_in_setting:-low} footprint=${fpm_footprint_in_setting:-low}
ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint
fi fi
fi fi
# Do not use a dedicated service by default
dedicated_service=${dedicated_service:-0}
# Set the default PHP-FPM version by default # Set the default PHP-FPM version by default
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
@ -123,51 +120,23 @@ ynh_add_fpm_config() {
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf" local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
if [[ -f "$old_php_finalphpconf" ]]; then if [[ -f "$old_php_finalphpconf" ]]
then
ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf" ynh_backup_if_checksum_is_different --file="$old_php_finalphpconf"
ynh_remove_fpm_config ynh_remove_fpm_config
fi fi
fi fi
# Legacy args (packager should just list their php dependency as regular apt dependencies... local fpm_service="php${phpversion}-fpm"
if [ -n "$package" ]; then local fpm_config_dir="/etc/php/$phpversion/fpm"
# Install the additionnal packages from the default repository
ynh_print_warn --message "Argument --package of ynh_add_fpm_config is deprecated and to be removed in the future"
ynh_install_app_dependencies "$package"
fi
if [ $dedicated_service -eq 1 ]; then
ynh_print_warn --message "Argument --dedicated_service of ynh_add_fpm_config is deprecated and to be removed in the future"
local fpm_service="${app}-phpfpm"
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
else
local fpm_service="php${phpversion}-fpm"
local fpm_config_dir="/etc/php/$phpversion/fpm"
fi
# Create the directory for FPM pools # Create the directory for FPM pools
mkdir --parents "$fpm_config_dir/pool.d" mkdir --parents "$fpm_config_dir/pool.d"
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service"
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
# Migrate from mutual PHP service to dedicated one.
if [ $dedicated_service -eq 1 ]; then
local old_fpm_config_dir="/etc/php/$phpversion/fpm"
# If a config file exist in the common pool, move it.
if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ]; then
ynh_print_info --message="Migrate to a dedicated php-fpm service for $app."
# Create a backup of the old file before migration
ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf"
# Remove the old PHP config file
ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf"
# Reload PHP to release the socket and allow the dedicated service to use it
ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload
fi
fi
if [ $autogenconf == "false" ]; then if [ $autogenconf == "false" ]; then
# Usage 1, use the template in conf/php-fpm.conf # Usage 1, use the template in conf/php-fpm.conf
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf" local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
@ -197,80 +166,37 @@ pm = __PHP_PM__
pm.max_children = __PHP_MAX_CHILDREN__ pm.max_children = __PHP_MAX_CHILDREN__
pm.max_requests = 500 pm.max_requests = 500
request_terminate_timeout = 1d request_terminate_timeout = 1d
" > "$phpfpm_path" " >"$phpfpm_path"
if [ "$php_pm" = "dynamic" ]; then if [ "$php_pm" = "dynamic" ]; then
echo " echo "
pm.start_servers = __PHP_START_SERVERS__ pm.start_servers = __PHP_START_SERVERS__
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__ pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__ pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
" >> "$phpfpm_path" " >>"$phpfpm_path"
elif [ "$php_pm" = "ondemand" ]; then elif [ "$php_pm" = "ondemand" ]; then
echo " echo "
pm.process_idle_timeout = 10s pm.process_idle_timeout = 10s
" >> "$phpfpm_path" " >>"$phpfpm_path"
fi fi
# Concatene the extra config. # Concatene the extra config.
if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then
cat $YNH_APP_BASEDIR/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 "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then # Validate that the new php conf doesn't break php-fpm entirely
ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." if ! php-fpm${phpversion} --test 2>/dev/null; then
ynh_add_config --template="php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini" php-fpm${phpversion} --test || true
fi ynh_secure_remove --file="$finalphpconf"
ynh_die --message="The new configuration broke php-fpm?"
if [ $dedicated_service -eq 1 ]; then
# Create a dedicated php-fpm.conf for the service
local globalphpconf=$fpm_config_dir/php-fpm-$app.conf
echo "[global]
pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid
error_log = /var/log/php/fpm-php.__APP__.log
syslog.ident = php-fpm-__APP__
include = __FINALPHPCONF__
" > $YNH_APP_BASEDIR/conf/php-fpm-$app.conf
ynh_add_config --template="php-fpm-$app.conf" --destination="$globalphpconf"
# Create a config for a dedicated PHP-FPM service for the app
echo "[Unit]
Description=PHP __PHPVERSION__ FastCGI Process Manager for __APP__
After=network.target
[Service]
Type=notify
PIDFile=/run/php/php__PHPVERSION__-fpm-__APP__.pid
ExecStart=/usr/sbin/php-fpm__PHPVERSION__ --nodaemonize --fpm-config __GLOBALPHPCONF__
ExecReload=/bin/kill -USR2 \$MAINPID
[Install]
WantedBy=multi-user.target
" > $YNH_APP_BASEDIR/conf/$fpm_service
# Create this dedicated PHP-FPM service
ynh_add_systemd_config --service=$fpm_service --template=$fpm_service
# Integrate the service in YunoHost admin panel
yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --description "Php-fpm dedicated to $app"
# Configure log rotate
ynh_use_logrotate --logfile=/var/log/php
# Restart the service, as this service is either stopped or only for this app
ynh_systemd_action --service_name=$fpm_service --action=restart
else
# Validate that the new php conf doesn't break php-fpm entirely
if ! php-fpm${phpversion} --test 2> /dev/null; then
php-fpm${phpversion} --test || true
ynh_secure_remove --file="$finalphpconf"
ynh_die --message="The new configuration broke php-fpm?"
fi
ynh_systemd_action --service_name=$fpm_service --action=reload
fi fi
ynh_systemd_action --service_name=$fpm_service --action=reload
} }
# Remove the dedicated PHP-FPM config # Remove the dedicated PHP-FPM config
@ -281,8 +207,6 @@ WantedBy=multi-user.target
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)
dedicated_service=${dedicated_service:-0}
# Get the version of PHP used by this app # Get the version of PHP used by this app
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
@ -296,69 +220,7 @@ ynh_remove_fpm_config() {
fi fi
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]; then ynh_systemd_action --service_name=$fpm_service --action=reload
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
fi
if [ $dedicated_service -eq 1 ]; then
# Remove the dedicated service PHP-FPM service for the app
ynh_remove_systemd_config --service=$fpm_service
# Remove the global PHP-FPM conf
ynh_secure_remove --file="$fpm_config_dir/php-fpm-$app.conf"
# Remove the service from the list of services known by YunoHost
yunohost service remove $fpm_service
elif ynh_package_is_installed --package="php${phpversion}-fpm"; then
ynh_systemd_action --service_name=$fpm_service --action=reload
fi
# If the PHP version used is not the default version for YunoHost
# The second part with YNH_APP_PURGE is an ugly hack to guess that we're inside the remove script
# (we don't actually care about its value, we just check its not empty hence it exists)
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] && [ -n "${YNH_APP_PURGE:-}" ] && dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
# Remove app dependencies ... but ideally should happen via an explicit call from packager
ynh_remove_app_dependencies
fi
}
# Install another version of PHP.
#
# [internal]
#
# Legacy, to be remove on bullseye
#
# usage: ynh_install_php --phpversion=phpversion [--package=packages]
# | arg: -v, --phpversion= - Version of PHP to install.
# | arg: -p, --package= - Additionnal PHP packages to install
#
# Requires YunoHost version 3.8.1 or higher.
ynh_install_php() {
# Declare an array to define the options of this helper.
local legacy_args=vp
local -A args_array=([v]=phpversion= [p]=package=)
local phpversion
local package
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
package=${package:-}
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]; then
ynh_die --message="Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
fi
ynh_install_app_dependencies "$package"
}
# Remove the specific version of PHP used by the app.
#
# [internal]
#
# Legacy, to be remove on bullseye
#
# usage: ynh_remove_php
#
# Requires YunoHost version 3.8.1 or higher.
ynh_remove_php() {
ynh_remove_app_dependencies
} }
# Define the values to configure PHP-FPM # Define the values to configure PHP-FPM

View file

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
PSQL_VERSION=13 PSQL_VERSION=15
# Open a connection as a user # Open a connection as a user
# #
@ -51,7 +51,7 @@ ynh_psql_execute_as_root() {
fi fi
ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \
$database <<< "$sql" $database <<<"$sql"
} }
# Execute a command from a file as root user # Execute a command from a file as root user
@ -76,7 +76,7 @@ ynh_psql_execute_file_as_root() {
fi fi
ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \
$database < "$file" $database <"$file"
} }
# Create a database and grant optionnaly privilegies to a user # Create a database and grant optionnaly privilegies to a user
@ -199,9 +199,10 @@ ynh_psql_database_exists() {
# if psql is not there, we cannot check the db # if psql is not there, we cannot check the db
# though it could exists. # though it could exists.
if ! command -v psql; then if ! command -v psql
ynh_print_err -m "PostgreSQL is not installed, impossible to check for db existence." then
return 1 ynh_print_err -m "PostgreSQL is not installed, impossible to check for db existence."
return 1
elif ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then elif ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then
return 1 return 1
else else

View file

@ -5,25 +5,27 @@
# usage: ynh_redis_get_free_db # usage: ynh_redis_get_free_db
# | returns: the database number to use # | returns: the database number to use
ynh_redis_get_free_db() { ynh_redis_get_free_db() {
local result max db local result max db
result=$(redis-cli INFO keyspace) result=$(redis-cli INFO keyspace)
# get the num # get the num
max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+") max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+")
db=0 db=0
# default Debian setting is 15 databases # default Debian setting is 15 databases
for i in $(seq 0 "$max"); do for i in $(seq 0 "$max")
if ! echo "$result" | grep -q "db$i"; then do
db=$i if ! echo "$result" | grep -q "db$i"
break 1 then
fi db=$i
db=-1 break 1
done fi
db=-1
done
test "$db" -eq -1 && ynh_die --message="No available Redis databases..." test "$db" -eq -1 && ynh_die --message="No available Redis databases..."
echo "$db" echo "$db"
} }
# Create a master password and set up global settings # Create a master password and set up global settings
@ -32,6 +34,6 @@ ynh_redis_get_free_db() {
# usage: ynh_redis_remove_db database # usage: ynh_redis_remove_db database
# | arg: database - the database to erase # | arg: database - the database to erase
ynh_redis_remove_db() { ynh_redis_remove_db() {
local db=$1 local db=$1
redis-cli -n "$db" flushdb redis-cli -n "$db" flushdb
} }

View file

@ -8,8 +8,8 @@ export RBENV_ROOT="$rbenv_install_dir"
export rbenv_root="$rbenv_install_dir" export rbenv_root="$rbenv_install_dir"
if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then if dpkg --compare-versions ${YNH_APP_PACKAGING_FORMAT:-0} lt 2; then
build_ruby_dependencies="libjemalloc-dev curl build-essential libreadline-dev zlib1g-dev libsqlite3-dev libssl-dev libxml2-dev libxslt-dev autoconf automake bison libtool" build_ruby_dependencies="libjemalloc-dev curl build-essential libreadline-dev zlib1g-dev libsqlite3-dev libssl-dev libxml2-dev libxslt-dev autoconf automake bison libtool"
build_pkg_dependencies="${build_pkg_dependencies:-} $build_ruby_dependencies" build_pkg_dependencies="${build_pkg_dependencies:-} $build_ruby_dependencies"
fi fi
# Load the version of Ruby for an app, and set variables. # Load the version of Ruby for an app, and set variables.
@ -50,7 +50,7 @@ fi
# usage: ynh_use_ruby # usage: ynh_use_ruby
# #
# Requires YunoHost version 3.2.2 or higher. # Requires YunoHost version 3.2.2 or higher.
ynh_use_ruby() { ynh_use_ruby () {
ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version) ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version)
# Get the absolute path of this version of Ruby # Get the absolute path of this version of Ruby
@ -75,7 +75,7 @@ ynh_use_ruby() {
# Sets the local application-specific Ruby version # Sets the local application-specific Ruby version
pushd ${install_dir:-$final_path} pushd ${install_dir:-$final_path}
$rbenv_install_dir/bin/rbenv local $ruby_version $rbenv_install_dir/bin/rbenv local $ruby_version
popd popd
} }
@ -95,10 +95,10 @@ ynh_use_ruby() {
# | arg: -v, --ruby_version= - Version of ruby to install. # | arg: -v, --ruby_version= - Version of ruby to install.
# #
# Requires YunoHost version 3.2.2 or higher. # Requires YunoHost version 3.2.2 or higher.
ynh_install_ruby() { ynh_install_ruby () {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=v local legacy_args=v
local -A args_array=([v]=ruby_version=) local -A args_array=( [v]=ruby_version= )
local ruby_version local ruby_version
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -117,31 +117,31 @@ ynh_install_ruby() {
rbenv="$(command -v rbenv $rbenv_install_dir/bin/rbenv | grep "$rbenv_install_dir/bin/rbenv" | head -1)" rbenv="$(command -v rbenv $rbenv_install_dir/bin/rbenv | grep "$rbenv_install_dir/bin/rbenv" | head -1)"
if [ -n "$rbenv" ]; then if [ -n "$rbenv" ]; then
pushd "${rbenv%/*/*}" pushd "${rbenv%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/rbenv/rbenv.git"; then if git remote -v 2>/dev/null | grep "https://github.com/rbenv/rbenv.git"; then
ynh_print_info --message="Updating rbenv..." ynh_print_info --message="Updating rbenv..."
git pull -q --tags origin master git pull -q --tags origin master
ynh_ruby_try_bash_extension ynh_ruby_try_bash_extension
else else
ynh_print_info --message="Reinstalling rbenv..." ynh_print_info --message="Reinstalling rbenv..."
cd .. cd ..
ynh_secure_remove --file=$rbenv_install_dir ynh_secure_remove --file=$rbenv_install_dir
mkdir -p $rbenv_install_dir mkdir -p $rbenv_install_dir
cd $rbenv_install_dir cd $rbenv_install_dir
git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master
ynh_ruby_try_bash_extension
rbenv=$rbenv_install_dir/bin/rbenv
fi
popd
else
ynh_print_info --message="Installing rbenv..."
pushd $rbenv_install_dir
git init -q git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1 git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master git checkout -q -b master origin/master
ynh_ruby_try_bash_extension ynh_ruby_try_bash_extension
rbenv=$rbenv_install_dir/bin/rbenv rbenv=$rbenv_install_dir/bin/rbenv
fi
popd
else
ynh_print_info --message="Installing rbenv..."
pushd $rbenv_install_dir
git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master
ynh_ruby_try_bash_extension
rbenv=$rbenv_install_dir/bin/rbenv
popd popd
fi fi
@ -150,10 +150,10 @@ ynh_install_ruby() {
ruby_build="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-install rbenv-install | head -1)" ruby_build="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-install rbenv-install | head -1)"
if [ -n "$ruby_build" ]; then if [ -n "$ruby_build" ]; then
pushd "${ruby_build%/*/*}" pushd "${ruby_build%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/rbenv/ruby-build.git"; then if git remote -v 2>/dev/null | grep "https://github.com/rbenv/ruby-build.git"; then
ynh_print_info --message="Updating ruby-build..." ynh_print_info --message="Updating ruby-build..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
ynh_print_info --message="Installing ruby-build..." ynh_print_info --message="Installing ruby-build..."
@ -163,10 +163,10 @@ ynh_install_ruby() {
rbenv_alias="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-alias rbenv-alias | head -1)" rbenv_alias="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-alias rbenv-alias | head -1)"
if [ -n "$rbenv_alias" ]; then if [ -n "$rbenv_alias" ]; then
pushd "${rbenv_alias%/*/*}" pushd "${rbenv_alias%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/tpope/rbenv-aliases.git"; then if git remote -v 2>/dev/null | grep "https://github.com/tpope/rbenv-aliases.git"; then
ynh_print_info --message="Updating rbenv-aliases..." ynh_print_info --message="Updating rbenv-aliases..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
ynh_print_info --message="Installing rbenv-aliases..." ynh_print_info --message="Installing rbenv-aliases..."
@ -176,10 +176,10 @@ ynh_install_ruby() {
rbenv_latest="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-latest rbenv-latest | head -1)" rbenv_latest="$(command -v "$rbenv_install_dir"/plugins/*/bin/rbenv-latest rbenv-latest | head -1)"
if [ -n "$rbenv_latest" ]; then if [ -n "$rbenv_latest" ]; then
pushd "${rbenv_latest%/*/*}" pushd "${rbenv_latest%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/momo-lab/xxenv-latest.git"; then if git remote -v 2>/dev/null | grep "https://github.com/momo-lab/xxenv-latest.git"; then
ynh_print_info --message="Updating xxenv-latest..." ynh_print_info --message="Updating xxenv-latest..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
ynh_print_info --message="Installing xxenv-latest..." ynh_print_info --message="Installing xxenv-latest..."
@ -210,7 +210,8 @@ ynh_install_ruby() {
ynh_app_setting_set --app=$app --key=ruby_version --value=$final_ruby_version ynh_app_setting_set --app=$app --key=ruby_version --value=$final_ruby_version
# Remove app virtualenv # Remove app virtualenv
if rbenv alias --list | grep --quiet "$app "; then if rbenv alias --list | grep --quiet "$app "
then
rbenv alias $app --remove rbenv alias $app --remove
fi fi
@ -221,7 +222,7 @@ ynh_install_ruby() {
ynh_cleanup_ruby ynh_cleanup_ruby
# Set environment for Ruby users # Set environment for Ruby users
echo "#rbenv echo "#rbenv
export RBENV_ROOT=$rbenv_install_dir export RBENV_ROOT=$rbenv_install_dir
export PATH=\"$rbenv_install_dir/bin:$PATH\" export PATH=\"$rbenv_install_dir/bin:$PATH\"
eval \"\$(rbenv init -)\" eval \"\$(rbenv init -)\"
@ -236,7 +237,7 @@ eval \"\$(rbenv init -)\"
# This helper will also cleanup Ruby versions # This helper will also cleanup Ruby versions
# #
# usage: ynh_remove_ruby # usage: ynh_remove_ruby
ynh_remove_ruby() { ynh_remove_ruby () {
local ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version) local ruby_version=$(ynh_app_setting_get --app=$app --key=ruby_version)
# Load rbenv path in PATH # Load rbenv path in PATH
@ -261,29 +262,34 @@ ynh_remove_ruby() {
# If no app uses Ruby, rbenv will be also removed. # If no app uses Ruby, rbenv will be also removed.
# #
# usage: ynh_cleanup_ruby # usage: ynh_cleanup_ruby
ynh_cleanup_ruby() { ynh_cleanup_ruby () {
# List required Ruby versions # List required Ruby versions
local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$') local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$')
local required_ruby_versions="" local required_ruby_versions=""
for installed_app in $installed_apps; do for installed_app in $installed_apps
do
local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version") local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version")
if [[ -n "$installed_app_ruby_version" ]]; then if [[ -n "$installed_app_ruby_version" ]]
then
required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}" required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}"
fi fi
done done
# Remove no more needed Ruby versions # Remove no more needed Ruby versions
local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/') local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/')
for installed_ruby_version in $installed_ruby_versions; do for installed_ruby_version in $installed_ruby_versions
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"; then do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"
then
ynh_print_info --message="Removing Ruby-$installed_ruby_version" ynh_print_info --message="Removing Ruby-$installed_ruby_version"
$rbenv_install_dir/bin/rbenv uninstall --force $installed_ruby_version $rbenv_install_dir/bin/rbenv uninstall --force $installed_ruby_version
fi fi
done done
# If none Ruby version is required # If none Ruby version is required
if [[ -z "$required_ruby_versions" ]]; then if [[ -z "$required_ruby_versions" ]]
then
# Remove rbenv environment configuration # Remove rbenv environment configuration
ynh_print_info --message="Removing rbenv" ynh_print_info --message="Removing rbenv"
ynh_secure_remove --file="$rbenv_install_dir" ynh_secure_remove --file="$rbenv_install_dir"
@ -292,9 +298,9 @@ ynh_cleanup_ruby() {
} }
ynh_ruby_try_bash_extension() { ynh_ruby_try_bash_extension() {
if [ -x src/configure ]; then if [ -x src/configure ]; then
src/configure && make -C src || { src/configure && make -C src || {
ynh_print_info --message="Optional bash extension failed to build, but things will still work normally." ynh_print_info --message="Optional bash extension failed to build, but things will still work normally."
} }
fi fi
} }

View file

@ -18,11 +18,7 @@ ynh_app_setting_get() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}" app="${app:-$_globalapp}"
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then ynh_app_setting "get" "$app" "$key"
yunohost app setting $app $key
else
ynh_app_setting "get" "$app" "$key"
fi
} }
# Set an application setting # Set an application setting
@ -45,11 +41,7 @@ ynh_app_setting_set() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}" app="${app:-$_globalapp}"
if [[ $key =~ (unprotected|protected|skipped)_ ]]; then ynh_app_setting "set" "$app" "$key" "$value"
yunohost app setting $app $key -v $value
else
ynh_app_setting "set" "$app" "$key" "$value"
fi
} }
# Set an application setting but only if the "$key" variable ain't set yet # Set an application setting but only if the "$key" variable ain't set yet
@ -106,11 +98,7 @@ ynh_app_setting_delete() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
app="${app:-$_globalapp}" app="${app:-$_globalapp}"
if [[ "$key" =~ (unprotected|skipped|protected)_ ]]; then ynh_app_setting "delete" "$app" "$key"
yunohost app setting $app $key -d
else
ynh_app_setting "delete" "$app" "$key"
fi
} }
# Small "hard-coded" interface to avoid calling "yunohost app" directly each # Small "hard-coded" interface to avoid calling "yunohost app" directly each
@ -120,7 +108,7 @@ ynh_app_setting_delete() {
# #
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
app, action = os.environ['APP'], os.environ['ACTION'].lower() app, action = os.environ['APP'], os.environ['ACTION'].lower()
key, value = os.environ['KEY'], os.environ.get('VALUE', None) key, value = os.environ['KEY'], os.environ.get('VALUE', None)

View file

@ -77,10 +77,12 @@ ynh_setup_source() {
keep="${keep:-}" keep="${keep:-}"
full_replace="${full_replace:-0}" full_replace="${full_replace:-0}"
if test -e $YNH_APP_BASEDIR/manifest.toml && cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq -e '.resources.sources' > /dev/null; then if test -e $YNH_APP_BASEDIR/manifest.toml && cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq -e '.resources.sources' >/dev/null
then
source_id="${source_id:-main}" source_id="${source_id:-main}"
local sources_json=$(cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq ".resources.sources[\"$source_id\"]") local sources_json=$(cat $YNH_APP_BASEDIR/manifest.toml | toml_to_json | jq ".resources.sources[\"$source_id\"]")
if jq -re ".url" <<< "$sources_json"; then if jq -re ".url" <<< "$sources_json"
then
local arch_prefix="" local arch_prefix=""
else else
local arch_prefix=".$YNH_ARCH" local arch_prefix=".$YNH_ARCH"
@ -98,16 +100,22 @@ ynh_setup_source() {
[[ -n "$src_url" ]] || ynh_die "No URL defined for source $source_id$arch_prefix ?" [[ -n "$src_url" ]] || ynh_die "No URL defined for source $source_id$arch_prefix ?"
[[ -n "$src_sum" ]] || ynh_die "No sha256 sum defined for source $source_id$arch_prefix ?" [[ -n "$src_sum" ]] || ynh_die "No sha256 sum defined for source $source_id$arch_prefix ?"
if [[ -z "$src_format" ]]; then if [[ -z "$src_format" ]]
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]; then then
if [[ "$src_url" =~ ^.*\.zip$ ]] || [[ "$src_url" =~ ^.*/zipball/.*$ ]]
then
src_format="zip" src_format="zip"
elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]; then elif [[ "$src_url" =~ ^.*\.tar\.gz$ ]] || [[ "$src_url" =~ ^.*\.tgz$ ]] || [[ "$src_url" =~ ^.*/tar\.gz/.*$ ]] || [[ "$src_url" =~ ^.*/tarball/.*$ ]]
then
src_format="tar.gz" src_format="tar.gz"
elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]; then elif [[ "$src_url" =~ ^.*\.tar\.xz$ ]]
then
src_format="tar.xz" src_format="tar.xz"
elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]; then elif [[ "$src_url" =~ ^.*\.tar\.bz2$ ]]
then
src_format="tar.bz2" src_format="tar.bz2"
elif [[ -z "$src_extract" ]]; then elif [[ -z "$src_extract" ]]
then
src_extract="false" src_extract="false"
fi fi
fi fi
@ -134,10 +142,12 @@ ynh_setup_source() {
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]') src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
src_extract=${src_extract:-true} src_extract=${src_extract:-true}
if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]; then if [[ "$src_extract" != "true" ]] && [[ "$src_extract" != "false" ]]
then
ynh_die "For source $source_id, expected either 'true' or 'false' for the extract parameter" ynh_die "For source $source_id, expected either 'true' or 'false' for the extract parameter"
fi fi
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it... # (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${source_id}" local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${source_id}"
@ -155,12 +165,14 @@ ynh_setup_source() {
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?" [ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
# If the file was prefetched but somehow doesn't match the sum, rm and redownload it # If the file was prefetched but somehow doesn't match the sum, rm and redownload it
if [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status; then if [ -e "$src_filename" ] && ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
rm -f "$src_filename" rm -f "$src_filename"
fi fi
# Only redownload the file if it wasnt prefetched # Only redownload the file if it wasnt prefetched
if [ ! -e "$src_filename" ]; then if [ ! -e "$src_filename" ]
then
# NB. we have to declare the var as local first, # 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 ...
@ -171,7 +183,8 @@ ynh_setup_source() {
fi fi
# Check the control sum # Check the control sum
if ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status; then if ! echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status
then
local actual_sum="$(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)" local actual_sum="$(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)"
local actual_size="$(du -hs ${src_filename} | cut --fields=1)" local actual_size="$(du -hs ${src_filename} | cut --fields=1)"
rm -f ${src_filename} rm -f ${src_filename}
@ -209,7 +222,8 @@ ynh_setup_source() {
fi fi
if [[ "$src_extract" == "false" ]]; then if [[ "$src_extract" == "false" ]]; then
if [[ -z "$src_rename" ]]; then if [[ -z "$src_rename" ]]
then
mv $src_filename $dest_dir mv $src_filename $dest_dir
else else
mv $src_filename $dest_dir/$src_rename mv $src_filename $dest_dir/$src_rename
@ -249,11 +263,11 @@ ynh_setup_source() {
# Apply patches # Apply patches
if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]; then if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]; then
local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/) local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/)
if (($(find $patches_folder -type f -name "${source_id}-*.patch" 2> /dev/null | wc --lines) > "0")); then if (($(find $patches_folder -type f -name "${source_id}-*.patch" 2>/dev/null | wc --lines) > "0")); then
pushd "$dest_dir" pushd "$dest_dir"
for p in $patches_folder/${source_id}-*.patch; do for p in $patches_folder/${source_id}-*.patch; do
echo $p echo $p
patch --strip=1 < $p || ynh_print_warn --message="Packagers /!\\ patch $p failed to apply" patch --strip=1 <$p || ynh_print_warn --message="Packagers /!\\ patch $p failed to apply"
done done
popd popd
fi fi

View file

@ -21,7 +21,7 @@ ynh_string_random() {
length=${length:-24} length=${length:-24}
filter=${filter:-'A-Za-z0-9'} filter=${filter:-'A-Za-z0-9'}
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \ dd if=/dev/urandom bs=1 count=1000 2>/dev/null \
| tr --complement --delete "$filter" \ | tr --complement --delete "$filter" \
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p' | sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
} }

View file

@ -94,12 +94,12 @@ ynh_systemd_action() {
# Following the starting of the app in its log # Following the starting of the app in its log
if [ "$log_path" == "systemd" ]; then if [ "$log_path" == "systemd" ]; 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
@ -149,7 +149,8 @@ ynh_systemd_action() {
# Also check the timeout using actual timestamp, because sometimes for some reason, # Also check the timeout using actual timestamp, because sometimes for some reason,
# journalctl may take a huge time to run, and we end up waiting literally an entire hour # journalctl may take a huge time to run, and we end up waiting literally an entire hour
# instead of 5 min ... # instead of 5 min ...
if [[ "$(($(date +%s) - $starttime))" -gt "$timeout" ]]; then if [[ "$(( $(date +%s) - $starttime))" -gt "$timeout" ]]
then
i=$timeout i=$timeout
break break
fi fi

View file

@ -17,7 +17,7 @@ ynh_system_user_exists() {
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
getent passwd "$username" &> /dev/null getent passwd "$username" &>/dev/null
} }
# Check if a group exists on the system # Check if a group exists on the system
@ -37,7 +37,7 @@ ynh_system_group_exists() {
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
getent group "$group" &> /dev/null getent group "$group" &>/dev/null
} }
# Create a system user # Create a system user

View file

@ -39,11 +39,11 @@
# This option is meant for advanced use-cases where the "simple" templating # This option is meant for advanced use-cases where the "simple" templating
# mode ain't enough because you need conditional blocks or loops. # mode ain't enough because you need conditional blocks or loops.
# #
# For a full documentation of jinja's syntax you can refer to: # For a full documentation of jinja's syntax you can refer to:
# https://jinja.palletsprojects.com/en/3.1.x/templates/ # https://jinja.palletsprojects.com/en/3.1.x/templates/
# #
# Note that in YunoHost context, all variables are from shell variables and therefore are strings # Note that in YunoHost context, all variables are from shell variables and therefore are strings
# #
# ##### Keeping track of manual changes by the admin # ##### Keeping track of manual changes by the admin
# #
# The helper will verify the checksum and backup the destination file # The helper will verify the checksum and backup the destination file
@ -83,9 +83,10 @@ ynh_add_config() {
chmod 640 $destination chmod 640 $destination
_ynh_apply_default_permissions $destination _ynh_apply_default_permissions $destination
if [[ "$jinja" == 1 ]]; then if [[ "$jinja" == 1 ]]
then
# This is ran in a subshell such that the "export" does not "contaminate" the main process # This is ran in a subshell such that the "export" does not "contaminate" the main process
( (
export $(compgen -v) export $(compgen -v)
j2 "$template_path" -f env -o $destination j2 "$template_path" -f env -o $destination
) )
@ -266,7 +267,7 @@ ynh_read_var_in_file() {
var_part+='\s*' var_part+='\s*'
# Extract the part after assignation sign # 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)" 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 if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x set -o xtrace # set -x
echo YNH_NULL echo YNH_NULL
@ -345,7 +346,7 @@ ynh_write_var_in_file() {
var_part+='\s*' var_part+='\s*'
# Extract the part after assignation sign # Extract the part after assignation sign
local expression_with_comment="$( (tail +$after_line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)" local expression_with_comment="$((tail +$after_line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)"
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x set -o xtrace # set -x
return 1 return 1
@ -402,5 +403,5 @@ 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
} }

View file

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

View file

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

View file

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

View file

@ -38,8 +38,8 @@ ynh_composer_exec() {
local workdir="${composer_workdir:-$install_dir}" local workdir="${composer_workdir:-$install_dir}"
COMPOSER_HOME="$workdir/.composer" \ COMPOSER_HOME="$workdir/.composer" \
COMPOSER_MEMORY_LIMIT=-1 \ COMPOSER_MEMORY_LIMIT=-1 \
sudo -E -u "${composer_user:-$app}" \ sudo -E -u "${composer_user:-$app}" \
php${php_version} "$workdir/composer.phar" $@ \ php${php_version} "$workdir/composer.phar" $@ \
-d "$workdir" --no-interaction --no-ansi 2>&1 -d "$workdir" --no-interaction --no-ansi 2>&1
} }

View file

@ -6,11 +6,11 @@ _ynh_app_config_get_one() {
local bind="$3" local bind="$3"
local getter="get__${short_setting}" local getter="get__${short_setting}"
# Get value from getter if exists # Get value from getter if exists
if type -t $getter 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
old[$short_setting]="$($getter)" old[$short_setting]="$($getter)"
formats[${short_setting}]="yaml" formats[${short_setting}]="yaml"
elif [[ "$bind" == *"("* ]] && type -t "get__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then 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)" old[$short_setting]="$("get__${bind%%(*}" $short_setting $type $bind)"
formats[${short_setting}]="yaml" formats[${short_setting}]="yaml"
@ -22,7 +22,7 @@ _ynh_app_config_get_one() {
if [[ "$bind" == "settings" ]]; then if [[ "$bind" == "settings" ]]; then
ynh_die "File '${short_setting}' can't be stored in settings" ynh_die "File '${short_setting}' can't be stored in settings"
fi fi
old[$short_setting]="$(ls "$bind" 2> /dev/null || echo YNH_NULL)" old[$short_setting]="$(ls "$(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)" 2>/dev/null || echo YNH_NULL)"
file_hash[$short_setting]="true" file_hash[$short_setting]="true"
# Get multiline text from settings or from a full file # Get multiline text from settings or from a full file
@ -32,7 +32,7 @@ _ynh_app_config_get_one() {
elif [[ "$bind" == *":"* ]]; then elif [[ "$bind" == *":"* ]]; then
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter" ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
else else
old[$short_setting]="$(cat "$bind" 2> /dev/null || echo YNH_NULL)" old[$short_setting]="$(cat $(echo $bind | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/) 2>/dev/null || echo YNH_NULL)"
fi fi
# Get value from a kind of key/value file # Get value from a kind of key/value file
@ -47,7 +47,7 @@ _ynh_app_config_get_one() {
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)" bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)" bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi fi
local bind_file="$(echo "$bind" | cut -d: -f2)" local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")" old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
fi fi
@ -59,10 +59,10 @@ _ynh_app_config_apply_one() {
local type="${types[$short_setting]}" local type="${types[$short_setting]}"
if [ "${changed[$short_setting]}" == "true" ]; then if [ "${changed[$short_setting]}" == "true" ]; then
# Apply setter if exists # Apply setter if exists
if type -t $setter 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
$setter $setter
elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then elif [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"set__${bind%%(*}" $short_setting $type $bind "set__${bind%%(*}" $short_setting $type $bind
elif [[ "$bind" == "null" ]]; then elif [[ "$bind" == "null" ]]; then
@ -73,7 +73,7 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == "settings" ]]; then if [[ "$bind" == "settings" ]]; then
ynh_die "File '${short_setting}' can't be stored in settings" ynh_die "File '${short_setting}' can't be stored in settings"
fi fi
local bind_file="$bind" local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
if [[ "${!short_setting}" == "" ]]; then if [[ "${!short_setting}" == "" ]]; then
ynh_backup_if_checksum_is_different "$bind_file" ynh_backup_if_checksum_is_different "$bind_file"
ynh_safe_rm "$bind_file" ynh_safe_rm "$bind_file"
@ -84,7 +84,8 @@ _ynh_app_config_apply_one() {
if [[ "${!short_setting}" != "$bind_file" ]]; then if [[ "${!short_setting}" != "$bind_file" ]]; then
cp "${!short_setting}" "$bind_file" cp "${!short_setting}" "$bind_file"
fi fi
if _ynh_file_checksum_exists "$bind_file"; then if _ynh_file_checksum_exists "$bind_file"
then
ynh_store_file_checksum "$bind_file" ynh_store_file_checksum "$bind_file"
fi fi
ynh_print_info "File '$bind_file' overwritten with ${!short_setting}" ynh_print_info "File '$bind_file' overwritten with ${!short_setting}"
@ -100,10 +101,11 @@ _ynh_app_config_apply_one() {
if [[ "$bind" == *":"* ]]; then if [[ "$bind" == *":"* ]]; then
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter" ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
fi fi
local bind_file="$bind" local bind_file="$(echo "$bind" | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different "$bind_file" ynh_backup_if_checksum_is_different "$bind_file"
echo "${!short_setting}" > "$bind_file" echo "${!short_setting}" >"$bind_file"
if _ynh_file_checksum_exists "$bind_file"; then if _ynh_file_checksum_exists "$bind_file"
then
ynh_store_file_checksum "$bind_file" ynh_store_file_checksum "$bind_file"
fi fi
ynh_print_info "File '$bind_file' overwritten with the content provided in question '${short_setting}'" ynh_print_info "File '$bind_file' overwritten with the content provided in question '${short_setting}'"
@ -117,11 +119,12 @@ _ynh_app_config_apply_one() {
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)" bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
fi fi
bind_key_=${bind_key_:-$short_setting} bind_key_=${bind_key_:-$short_setting}
local bind_file="$(echo "$bind" | cut -d: -f2)" local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__INSTALL_DIR__@${install_dir:-}@ | sed s/__APP__/$app/)"
ynh_backup_if_checksum_is_different "$bind_file" ynh_backup_if_checksum_is_different "$bind_file"
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}" ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
if _ynh_file_checksum_exists "$bind_file"; then if _ynh_file_checksum_exists "$bind_file"
then
ynh_store_file_checksum "$bind_file" ynh_store_file_checksum "$bind_file"
fi fi
@ -132,17 +135,69 @@ _ynh_app_config_apply_one() {
fi fi
fi fi
} }
_ynh_app_config_get() { _ynh_app_config_get() {
for line in $YNH_APP_CONFIG_PANEL_OPTIONS_TYPES_AND_BINDS; do # From settings
local lines
lines=$(
python3 <<EOL
import toml
from collections import OrderedDict
with open("../config_panel.toml", "r") as f:
file_content = f.read()
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
for panel_name, panel in loaded_toml.items():
if not isinstance(panel, dict): continue
bind_panel = panel.get('bind')
for section_name, section in panel.items():
if not isinstance(section, dict): continue
bind_section = section.get('bind')
if not bind_section:
bind_section = bind_panel
elif bind_section[-1] == ":" and bind_panel and ":" in bind_panel:
regex, bind_panel_file = bind_panel.split(":")
if ">" in bind_section:
bind_section = bind_section + bind_panel_file
else:
bind_section = regex + bind_section + bind_panel_file
for name, param in section.items():
if not isinstance(param, dict):
continue
bind = param.get('bind')
if not bind:
if bind_section:
bind = bind_section
else:
bind = 'settings'
elif bind[-1] == ":" and bind_section and ":" in bind_section:
regex, bind_file = bind_section.split(":")
if ">" in bind:
bind = bind + bind_file
else:
bind = regex + bind + bind_file
if bind == "settings" and param.get('type', 'string') == 'file':
bind = 'null'
print('|'.join([
name,
param.get('type', 'string'),
bind
]))
EOL
)
for line in $lines; do
# Split line into short_setting, type and bind # Split line into short_setting, type and bind
IFS='|' read short_setting type bind <<< "$line" IFS='|' read short_setting type bind <<<"$line"
binds[${short_setting}]="$bind" binds[${short_setting}]="$bind"
types[${short_setting}]="$type" types[${short_setting}]="$type"
file_hash[${short_setting}]="" file_hash[${short_setting}]=""
formats[${short_setting}]="" formats[${short_setting}]=""
ynh_app_config_get_one $short_setting $type $bind ynh_app_config_get_one $short_setting $type $bind
done done
} }
_ynh_app_config_apply() { _ynh_app_config_apply() {
@ -212,9 +267,9 @@ _ynh_app_config_validate() {
for short_setting in "${!old[@]}"; do for short_setting in "${!old[@]}"; do
[[ "${changed[$short_setting]}" == "false" ]] && continue [[ "${changed[$short_setting]}" == "false" ]] && continue
local result="" local result=""
if type -t validate__$short_setting | grep -q '^function$' 2> /dev/null; then if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
result="$(validate__$short_setting)" result="$(validate__$short_setting)"
elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2> /dev/null | grep -q '^function$' 2> /dev/null; then elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
"validate__${bind%%(*}" $short_setting "validate__${bind%%(*}" $short_setting
fi fi
if [ -n "$result" ]; then if [ -n "$result" ]; then
@ -269,7 +324,7 @@ ynh_app_config_apply() {
ynh_app_action_run() { ynh_app_action_run() {
local runner="run__$1" local runner="run__$1"
# Get value from getter if exists # Get value from getter if exists
if type -t "$runner" 2> /dev/null | grep -q '^function$' 2> /dev/null; then if type -t "$runner" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
$runner $runner
#ynh_return "result:" #ynh_return "result:"
#ynh_return "$(echo "${result}" | sed 's/^/ /g')" #ynh_return "$(echo "${result}" | sed 's/^/ /g')"
@ -287,23 +342,22 @@ ynh_app_config_run() {
declare -Ag formats=() declare -Ag formats=()
case $1 in case $1 in
show) show)
ynh_app_config_get ynh_app_config_get
ynh_app_config_show ynh_app_config_show
;; ;;
apply) apply)
max_progression=4 max_progression=4
ynh_script_progression "Reading config panel description and current configuration..." ynh_script_progression "Reading config panel description and current configuration..."
ynh_app_config_get ynh_app_config_get
ynh_app_config_validate ynh_app_config_validate
ynh_script_progression "Applying the new configuration..." ynh_script_progression "Applying the new configuration..."
ynh_app_config_apply ynh_app_config_apply
ynh_script_progression "Configuration of $app completed" ynh_script_progression "Configuration of $app completed"
;; ;;
*) *)
ynh_app_action_run $1 ynh_app_action_run $1
;;
esac esac
} }

View file

@ -68,7 +68,7 @@ port = http,https
filter = __APP__ filter = __APP__
logpath = __LOGPATH__ logpath = __LOGPATH__
maxretry = 5 maxretry = 5
" > "$YNH_APP_BASEDIR/conf/f2b_jail.conf" " >"$YNH_APP_BASEDIR/conf/f2b_jail.conf"
echo " echo "
[INCLUDES] [INCLUDES]
@ -76,7 +76,7 @@ before = common.conf
[Definition] [Definition]
failregex = __FAILREGEX__ failregex = __FAILREGEX__
ignoreregex = ignoreregex =
" > "$YNH_APP_BASEDIR/conf/f2b_filter.conf" " >"$YNH_APP_BASEDIR/conf/f2b_filter.conf"
fi fi
ynh_config_add --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf" ynh_config_add --template="f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"

View file

@ -20,7 +20,7 @@
# | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function # | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function
# #
# This helper need an array, named "args_array" with all the arguments used by the helper # This helper need an array, named "args_array" with all the arguments used by the helper
# that want to use ynh_handle_getopts_args # that want to use ynh_handle_getopts_args
# Be carreful, this array has to be an associative array, as the following example: # Be carreful, this array has to be an associative array, as the following example:
# local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 ) # local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
# Let's explain this array: # Let's explain this array:
@ -50,7 +50,8 @@ ynh_handle_getopts_args() {
eval "$xtrace_enable" eval "$xtrace_enable"
return return
# Validate that the first char is - because it should be something like --option=value or -o ... # Validate that the first char is - because it should be something like --option=value or -o ...
elif [[ "${1:0:1}" != "-" ]]; then elif [[ "${1:0:1}" != "-" ]]
then
ynh_die "It looks like you called the helper using positional arguments instead of keyword arguments ?" ynh_die "It looks like you called the helper using positional arguments instead of keyword arguments ?"
fi fi
@ -181,6 +182,6 @@ ynh_handle_getopts_args() {
# Call parse_arg and pass the modified list of args as an array of arguments. # Call parse_arg and pass the modified list of args as an array of arguments.
parse_arg "${arguments[@]}" parse_arg "${arguments[@]}"
eval "$xtrace_enable" eval "$xtrace_enable"
} }

View file

@ -23,7 +23,7 @@ _ynh_load_go_in_path_and_other_tweaks() {
# Sets the local application-specific go version # Sets the local application-specific go version
pushd ${install_dir} pushd ${install_dir}
$GOENV_INSTALL_DIR/bin/goenv local $go_version $GOENV_INSTALL_DIR/bin/goenv local $go_version
popd popd
} }
@ -39,7 +39,7 @@ _ynh_load_go_in_path_and_other_tweaks() {
# - `$go_dir` (the directory containing the specific go version) # - `$go_dir` (the directory containing the specific go version)
# #
# This helper also creates a /etc/profile.d/goenv.sh that configures PATH environment for goenv # This helper also creates a /etc/profile.d/goenv.sh that configures PATH environment for goenv
ynh_go_install() { ynh_go_install () {
[[ -n "${go_version:-}" ]] || ynh_die "\$go_version should be defined prior to calling ynh_go_install" [[ -n "${go_version:-}" ]] || ynh_die "\$go_version should be defined prior to calling ynh_go_install"
@ -55,33 +55,33 @@ ynh_go_install() {
# Install or update goenv # Install or update goenv
mkdir -p $GOENV_INSTALL_DIR mkdir -p $GOENV_INSTALL_DIR
pushd "$GOENV_INSTALL_DIR" pushd "$GOENV_INSTALL_DIR"
if ! [ -x "$GOENV_INSTALL_DIR/bin/goenv" ]; then if ! [ -x "$GOENV_INSTALL_DIR/bin/goenv" ]; then
ynh_print_info "Downloading goenv..." ynh_print_info "Downloading goenv..."
git init -q git init -q
git remote add origin https://github.com/syndbg/goenv.git git remote add origin https://github.com/syndbg/goenv.git
else else
ynh_print_info "Updating goenv..." ynh_print_info "Updating goenv..."
fi fi
git fetch -q --tags --prune origin git fetch -q --tags --prune origin
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
git checkout -q "$git_latest_tag" git checkout -q "$git_latest_tag"
_ynh_go_try_bash_extension _ynh_go_try_bash_extension
goenv=$GOENV_INSTALL_DIR/bin/goenv goenv=$GOENV_INSTALL_DIR/bin/goenv
popd popd
# Install or update xxenv-latest # Install or update xxenv-latest
mkdir -p "$GOENV_INSTALL_DIR/plugins/xxenv-latest" mkdir -p "$GOENV_INSTALL_DIR/plugins/xxenv-latest"
pushd "$GOENV_INSTALL_DIR/plugins/xxenv-latest" pushd "$GOENV_INSTALL_DIR/plugins/xxenv-latest"
if ! [ -x "$GOENV_INSTALL_DIR/plugins/xxenv-latest/bin/goenv-latest" ]; then if ! [ -x "$GOENV_INSTALL_DIR/plugins/xxenv-latest/bin/goenv-latest" ]; then
ynh_print_info "Downloading xxenv-latest..." ynh_print_info "Downloading xxenv-latest..."
git init -q git init -q
git remote add origin https://github.com/momo-lab/xxenv-latest.git git remote add origin https://github.com/momo-lab/xxenv-latest.git
else else
ynh_print_info "Updating xxenv-latest..." ynh_print_info "Updating xxenv-latest..."
fi fi
git fetch -q --tags --prune origin git fetch -q --tags --prune origin
local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") local git_latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
git checkout -q "$git_latest_tag" git checkout -q "$git_latest_tag"
popd popd
# Enable caching # Enable caching
@ -109,7 +109,7 @@ ynh_go_install() {
_ynh_go_cleanup _ynh_go_cleanup
# Set environment for Go users # Set environment for Go users
echo "#goenv echo "#goenv
export GOENV_ROOT=$GOENV_INSTALL_DIR export GOENV_ROOT=$GOENV_INSTALL_DIR
export PATH=\"$GOENV_INSTALL_DIR/bin:$PATH\" export PATH=\"$GOENV_INSTALL_DIR/bin:$PATH\"
eval \"\$(goenv init -)\" eval \"\$(goenv init -)\"
@ -126,7 +126,7 @@ eval \"\$(goenv init -)\"
# This helper will also cleanup Go versions # This helper will also cleanup Go versions
# #
# usage: ynh_go_remove # usage: ynh_go_remove
ynh_go_remove() { ynh_go_remove () {
local go_version=$(ynh_app_setting_get --key="go_version") local go_version=$(ynh_app_setting_get --key="go_version")
# Load goenv path in PATH # Load goenv path in PATH
@ -151,29 +151,34 @@ ynh_go_remove() {
# If no app uses Go, goenv will be also removed. # If no app uses Go, goenv will be also removed.
# #
# usage: _ynh_go_cleanup # usage: _ynh_go_cleanup
_ynh_go_cleanup() { _ynh_go_cleanup () {
# List required Go versions # List required Go versions
local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id) local installed_apps=$(yunohost app list --output-as json --quiet | jq -r .apps[].id)
local required_go_versions="" local required_go_versions=""
for installed_app in $installed_apps; do for installed_app in $installed_apps
do
local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version") local installed_app_go_version=$(ynh_app_setting_get --app=$installed_app --key="go_version")
if [[ $installed_app_go_version ]]; then if [[ $installed_app_go_version ]]
then
required_go_versions="${installed_app_go_version}\n${required_go_versions}" required_go_versions="${installed_app_go_version}\n${required_go_versions}"
fi fi
done done
# Remove no more needed Go versions # Remove no more needed Go versions
local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/') local installed_go_versions=$(goenv versions --bare --skip-aliases | grep -Ev '/')
for installed_go_version in $installed_go_versions; do for installed_go_version in $installed_go_versions
if ! $(echo ${required_go_versions} | grep "${installed_go_version}" 1> /dev/null 2>&1); then do
if ! `echo ${required_go_versions} | grep "${installed_go_version}" 1>/dev/null 2>&1`
then
ynh_print_info "Removing of Go-$installed_go_version" ynh_print_info "Removing of Go-$installed_go_version"
$GOENV_INSTALL_DIR/bin/goenv uninstall --force "$installed_go_version" $GOENV_INSTALL_DIR/bin/goenv uninstall --force "$installed_go_version"
fi fi
done done
# If none Go version is required # If none Go version is required
if [[ ! $required_go_versions ]]; then if [[ ! $required_go_versions ]]
then
# Remove goenv environment configuration # Remove goenv environment configuration
ynh_print_info "Removing of goenv" ynh_print_info "Removing of goenv"
ynh_safe_rm "$GOENV_INSTALL_DIR" ynh_safe_rm "$GOENV_INSTALL_DIR"
@ -182,9 +187,9 @@ _ynh_go_cleanup() {
} }
_ynh_go_try_bash_extension() { _ynh_go_try_bash_extension() {
if [ -x src/configure ]; then if [ -x src/configure ]; then
src/configure && make -C src || { src/configure && make -C src || {
ynh_print_info "Optional bash extension failed to build, but things will still work normally." ynh_print_info "Optional bash extension failed to build, but things will still work normally."
} }
fi fi
} }

View file

@ -5,9 +5,11 @@
# usage: ynh_die "Some message" # usage: ynh_die "Some message"
ynh_die() { ynh_die() {
set +o xtrace # set +x set +o xtrace # set +x
if [[ -n "${1:-}" ]]; then if [[ -n "${1:-}" ]]
if [[ -n "${YNH_STDRETURN:-}" ]]; then then
python3 -c 'import yaml, sys; print(yaml.dump({"error": sys.stdin.read()}))' <<< "${1:-}" >> "$YNH_STDRETURN" if [[ -n "${YNH_STDRETURN:-}" ]]
then
python3 -c 'import yaml, sys; print(yaml.dump({"error": sys.stdin.read()}))' <<< "${1:-}" >>"$YNH_STDRETURN"
fi fi
echo "${1:-}" 1>&2 echo "${1:-}" 1>&2
fi fi
@ -49,7 +51,7 @@ ynh_exec_and_print_stderr_only_if_error() {
rc=0 rc=0
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077 # Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
"$@" 2> "$logfile" || rc="$?" "$@" 2> "$logfile" || rc="$?"
if ((rc != 0)); then if (( rc != 0 )); then
cat "$logfile" >&2 cat "$logfile" >&2
ynh_safe_rm "$logfile" ynh_safe_rm "$logfile"
return "$rc" return "$rc"
@ -61,7 +63,7 @@ ynh_exec_and_print_stderr_only_if_error() {
# #
# usage: ynh_return somedata # usage: ynh_return somedata
ynh_return() { ynh_return() {
echo "$1" >> "$YNH_STDRETURN" echo "$1" >>"$YNH_STDRETURN"
} }
# Initial definitions for ynh_script_progression # Initial definitions for ynh_script_progression
@ -103,9 +105,10 @@ ynh_script_progression() {
local expected_progression="$((($increment_progression + 1) * $progress_scale / $max_progression - $effective_progression))" local expected_progression="$((($increment_progression + 1) * $progress_scale / $max_progression - $effective_progression))"
# Hack for the "--last" message # Hack for the "--last" message
if grep -qw 'completed' <<< "$1"; then if grep -qw 'completed' <<< "$1";
effective_progression=$progress_scale then
expected_progression=0 effective_progression=$progress_scale
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))"

View file

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

View file

@ -12,15 +12,16 @@
# #
ynh_mongo_exec() { ynh_mongo_exec() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([d]=database= [c]=command=) local -A args_array=( [d]=database= [c]=command= )
local database local database
local command local command
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
database="${database:-}" database="${database:-}"
# =========================================== # ===========================================
if [ -n "$database" ]; then if [ -n "$database" ]
mongosh --quiet << EOF then
mongosh --quiet <<EOF
use $database use $database
${command} ${command}
quit() quit()
@ -43,7 +44,7 @@ EOF
# #
ynh_mongo_drop_db() { ynh_mongo_drop_db() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([d]=database=) local -A args_array=( [d]=database= )
local database local database
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
@ -62,7 +63,7 @@ ynh_mongo_drop_db() {
# #
ynh_mongo_dump_db() { ynh_mongo_dump_db() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([d]=database=) local -A args_array=( [d]=database= )
local database local database
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
@ -82,7 +83,7 @@ ynh_mongo_dump_db() {
# #
ynh_mongo_create_user() { ynh_mongo_create_user() {
# ============ Argument parsing ============= # ============ Argument parsing =============
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
local db_pwd local db_pwd
@ -110,7 +111,8 @@ ynh_mongo_database_exists() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")') -lt 0 ]; then if [ $(ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("'${database}'")') -lt 0 ]
then
return 1 return 1
else else
return 0 return 0
@ -127,7 +129,7 @@ ynh_mongo_database_exists() {
# #
ynh_mongo_restore_db() { ynh_mongo_restore_db() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([d]=database=) local -A args_array=( [d]=database= )
local database local database
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
@ -146,7 +148,7 @@ ynh_mongo_restore_db() {
# #
ynh_mongo_drop_user() { ynh_mongo_drop_user() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([u]=db_user= [n]=db_name=) local -A args_array=( [u]=db_user= [n]=db_name= )
local db_user local db_user
local db_name local db_name
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
@ -168,7 +170,7 @@ ynh_mongo_drop_user() {
# #
ynh_mongo_setup_db() { ynh_mongo_setup_db() {
# ============ Argument parsing ============= # ============ Argument parsing =============
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=""
@ -195,14 +197,14 @@ ynh_mongo_setup_db() {
# #
ynh_mongo_remove_db() { ynh_mongo_remove_db() {
# ============ Argument parsing ============= # ============ Argument parsing =============
local -A args_array=([u]=db_user= [n]=db_name=) local -A args_array=( [u]=db_user= [n]=db_name= )
local db_user local db_user
local db_name local db_name
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
if ynh_mongo_database_exists --database=$db_name; then # Check if the database exists if ynh_mongo_database_exists --database=$db_name; then # Check if the database exists
ynh_mongo_drop_db --database=$db_name # Remove the database ynh_mongo_drop_db --database=$db_name # Remove the database
else else
ynh_print_warn "Database $db_name not found" ynh_print_warn "Database $db_name not found"
fi fi
@ -260,7 +262,8 @@ ynh_install_mongo() {
# #
ynh_remove_mongo() { ynh_remove_mongo() {
# Only remove the mongodb service if it is not installed. # Only remove the mongodb service if it is not installed.
if ! _ynh_apt_package_is_installed "mongodb*"; then if ! _ynh_apt_package_is_installed "mongodb*"
then
ynh_print_info "Removing MongoDB service..." ynh_print_info "Removing MongoDB service..."
mongodb_servicename=mongod mongodb_servicename=mongod
# Remove the mongodb service # Remove the mongodb service

View file

@ -39,6 +39,7 @@ ynh_config_remove_nginx() {
ynh_systemctl --service=nginx --action=reload ynh_systemctl --service=nginx --action=reload
} }
# Regen the nginx config in a change url context # Regen the nginx config in a change url context
# #
# usage: ynh_config_change_url_nginx # usage: ynh_config_change_url_nginx
@ -46,7 +47,7 @@ ynh_config_change_url_nginx() {
# Make a backup of the original NGINX config file if manually modified # Make a backup of the original NGINX config file if manually modified
# (nb: this is possibly different from the same instruction called by # (nb: this is possibly different from the same instruction called by
# ynh_config_add inside ynh_config_add_nginx because the path may have # ynh_config_add inside ynh_config_add_nginx because the path may have
# changed if we're changing the domain too...) # changed if we're changing the domain too...)
local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf local old_nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
ynh_backup_if_checksum_is_different "$old_nginx_conf_path" ynh_backup_if_checksum_is_different "$old_nginx_conf_path"

View file

@ -169,7 +169,7 @@ ynh_permission_exists() {
# =========================================== # ===========================================
yunohost user permission list "$app" --output-as json --quiet \ yunohost user permission list "$app" --output-as json --quiet \
| jq -e --arg perm "$app.$permission" '.permissions[$perm]' > /dev/null | jq -e --arg perm "$app.$permission" '.permissions[$perm]' >/dev/null
} }
# Redefine the url associated to a permission # Redefine the url associated to a permission
@ -301,7 +301,7 @@ ynh_permission_has_user() {
# Check both allowed and corresponding_users sections in the json # Check both allowed and corresponding_users sections in the json
for section in "allowed" "corresponding_users"; do for section in "allowed" "corresponding_users"; do
if yunohost user permission info "$app.$permission" --output-as json --quiet \ 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 | jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null; then
return 0 return 0
fi fi
done done

View file

@ -59,9 +59,9 @@ ynh_config_add_phpfpm() {
# Apps willing to tweak these should use ynh_setting_set_default_value (in install and upgrade?) # Apps willing to tweak these should use ynh_setting_set_default_value (in install and upgrade?)
# #
local php_upload_max_filesize=${php_upload_max_filesize:-50M} local php_upload_max_filesize=${php_upload_max_filesize:-50M}
local php_process_management=${php_process_management:-ondemand} # alternatively 'dynamic' or 'static' local php_process_management=${php_process_management:-ondemand} # alternatively 'dynamic' or 'static'
local php_max_children=${php_max_children:-$(_default_php_max_children)} local php_max_children=${php_max_children:-$(_default_php_max_children)}
local php_memory_limit=${php_memory_limit:-128M} # default value is from global php.ini local php_memory_limit=${php_memory_limit:-128M} # default value is from global php.ini
local phpfpm_template=$(mktemp) local phpfpm_template=$(mktemp)
cat << EOF > $phpfpm_template cat << EOF > $phpfpm_template
@ -102,7 +102,7 @@ EOF
# Concatene the extra config # Concatene the extra config
if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then
cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >> "$phpfpm_template" cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >>"$phpfpm_template"
fi fi
# Make sure the fpm pool dir exists # Make sure the fpm pool dir exists
@ -111,7 +111,7 @@ EOF
ynh_config_add --template="$phpfpm_template" --destination="/etc/php/$php_version/fpm/pool.d/$app.conf" ynh_config_add --template="$phpfpm_template" --destination="/etc/php/$php_version/fpm/pool.d/$app.conf"
# 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${php_version} --test 2> /dev/null; then if ! php-fpm${php_version} --test 2>/dev/null; then
php-fpm${php_version} --test || true php-fpm${php_version} --test || true
ynh_safe_rm "/etc/php/$php_version/fpm/pool.d/$app.conf" ynh_safe_rm "/etc/php/$php_version/fpm/pool.d/$app.conf"
ynh_die "The new configuration broke php-fpm?" ynh_die "The new configuration broke php-fpm?"

View file

@ -5,25 +5,27 @@
# usage: ynh_redis_get_free_db # usage: ynh_redis_get_free_db
# | returns: the database number to use # | returns: the database number to use
ynh_redis_get_free_db() { ynh_redis_get_free_db() {
local result max db local result max db
result=$(redis-cli INFO keyspace) result=$(redis-cli INFO keyspace)
# get the num # get the num
max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+") max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+")
db=0 db=0
# default Debian setting is 15 databases # default Debian setting is 15 databases
for i in $(seq 0 "$max"); do for i in $(seq 0 "$max")
if ! echo "$result" | grep -q "db$i"; then do
db=$i if ! echo "$result" | grep -q "db$i"
break 1 then
fi db=$i
db=-1 break 1
done fi
db=-1
done
test "$db" -eq -1 && ynh_die "No available Redis databases..." test "$db" -eq -1 && ynh_die "No available Redis databases..."
echo "$db" echo "$db"
} }
# Create a master password and set up global settings # Create a master password and set up global settings
@ -32,6 +34,6 @@ ynh_redis_get_free_db() {
# usage: ynh_redis_remove_db database # usage: ynh_redis_remove_db database
# | arg: database - the database to erase # | arg: database - the database to erase
ynh_redis_remove_db() { ynh_redis_remove_db() {
local db=$1 local db=$1
redis-cli -n "$db" flushdb redis-cli -n "$db" flushdb
} }

View file

@ -25,7 +25,7 @@ _ynh_load_ruby_in_path_and_other_tweaks() {
# Sets the local application-specific Ruby version # Sets the local application-specific Ruby version
pushd ${install_dir} pushd ${install_dir}
$RBENV_INSTALL_DIR/bin/rbenv local $ruby_version $RBENV_INSTALL_DIR/bin/rbenv local $ruby_version
popd popd
} }
@ -41,7 +41,7 @@ _ynh_load_ruby_in_path_and_other_tweaks() {
# - `$ruby_dir`, the directory containing the specific version of ruby, which may be used in the systemd config too (e.g. `ExecStart=__RUBY_DIR__/ruby foo bar`) # - `$ruby_dir`, the directory containing the specific version of ruby, which may be used in the systemd config too (e.g. `ExecStart=__RUBY_DIR__/ruby foo bar`)
# #
# This helper also creates a /etc/profile.d/rbenv.sh that configures PATH environment for rbenv # This helper also creates a /etc/profile.d/rbenv.sh that configures PATH environment for rbenv
ynh_ruby_install() { ynh_ruby_install () {
[[ -n "${ruby_version:-}" ]] || ynh_die "\$ruby_version should be defined prior to calling ynh_ruby_install" [[ -n "${ruby_version:-}" ]] || ynh_die "\$ruby_version should be defined prior to calling ynh_ruby_install"
@ -59,31 +59,31 @@ ynh_ruby_install() {
rbenv="$(command -v rbenv $RBENV_INSTALL_DIR/bin/rbenv | grep "$RBENV_INSTALL_DIR/bin/rbenv" | head -1)" rbenv="$(command -v rbenv $RBENV_INSTALL_DIR/bin/rbenv | grep "$RBENV_INSTALL_DIR/bin/rbenv" | head -1)"
if [ -n "$rbenv" ]; then if [ -n "$rbenv" ]; then
pushd "${rbenv%/*/*}" pushd "${rbenv%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/rbenv/rbenv.git"; then if git remote -v 2>/dev/null | grep "https://github.com/rbenv/rbenv.git"; then
echo "Updating rbenv..." echo "Updating rbenv..."
git pull -q --tags origin master git pull -q --tags origin master
_ynh_ruby_try_bash_extension _ynh_ruby_try_bash_extension
else else
echo "Reinstalling rbenv..." echo "Reinstalling rbenv..."
cd .. cd ..
ynh_safe_rm $RBENV_INSTALL_DIR ynh_safe_rm $RBENV_INSTALL_DIR
mkdir -p $RBENV_INSTALL_DIR mkdir -p $RBENV_INSTALL_DIR
cd $RBENV_INSTALL_DIR cd $RBENV_INSTALL_DIR
git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master
_ynh_ruby_try_bash_extension
rbenv=$RBENV_INSTALL_DIR/bin/rbenv
fi
popd
else
echo "Installing rbenv..."
pushd $RBENV_INSTALL_DIR
git init -q git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1 git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master git checkout -q -b master origin/master
_ynh_ruby_try_bash_extension _ynh_ruby_try_bash_extension
rbenv=$RBENV_INSTALL_DIR/bin/rbenv rbenv=$RBENV_INSTALL_DIR/bin/rbenv
fi
popd
else
echo "Installing rbenv..."
pushd $RBENV_INSTALL_DIR
git init -q
git remote add -f -t master origin https://github.com/rbenv/rbenv.git > /dev/null 2>&1
git checkout -q -b master origin/master
_ynh_ruby_try_bash_extension
rbenv=$RBENV_INSTALL_DIR/bin/rbenv
popd popd
fi fi
@ -92,10 +92,10 @@ ynh_ruby_install() {
ruby_build="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-install rbenv-install | head -1)" ruby_build="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-install rbenv-install | head -1)"
if [ -n "$ruby_build" ]; then if [ -n "$ruby_build" ]; then
pushd "${ruby_build%/*/*}" pushd "${ruby_build%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/rbenv/ruby-build.git"; then if git remote -v 2>/dev/null | grep "https://github.com/rbenv/ruby-build.git"; then
echo "Updating ruby-build..." echo "Updating ruby-build..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
echo "Installing ruby-build..." echo "Installing ruby-build..."
@ -105,10 +105,10 @@ ynh_ruby_install() {
rbenv_alias="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-alias rbenv-alias | head -1)" rbenv_alias="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-alias rbenv-alias | head -1)"
if [ -n "$rbenv_alias" ]; then if [ -n "$rbenv_alias" ]; then
pushd "${rbenv_alias%/*/*}" pushd "${rbenv_alias%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/tpope/rbenv-aliases.git"; then if git remote -v 2>/dev/null | grep "https://github.com/tpope/rbenv-aliases.git"; then
echo "Updating rbenv-aliases..." echo "Updating rbenv-aliases..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
echo "Installing rbenv-aliases..." echo "Installing rbenv-aliases..."
@ -118,10 +118,10 @@ ynh_ruby_install() {
rbenv_latest="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-latest rbenv-latest | head -1)" rbenv_latest="$(command -v "$RBENV_INSTALL_DIR"/plugins/*/bin/rbenv-latest rbenv-latest | head -1)"
if [ -n "$rbenv_latest" ]; then if [ -n "$rbenv_latest" ]; then
pushd "${rbenv_latest%/*/*}" pushd "${rbenv_latest%/*/*}"
if git remote -v 2> /dev/null | grep "https://github.com/momo-lab/xxenv-latest.git"; then if git remote -v 2>/dev/null | grep "https://github.com/momo-lab/xxenv-latest.git"; then
echo "Updating xxenv-latest..." echo "Updating xxenv-latest..."
git pull -q origin master git pull -q origin master
fi fi
popd popd
else else
echo "Installing xxenv-latest..." echo "Installing xxenv-latest..."
@ -153,7 +153,8 @@ ynh_ruby_install() {
ruby_version=$final_ruby_version ruby_version=$final_ruby_version
# Remove app virtualenv # Remove app virtualenv
if rbenv alias --list | grep --quiet "$app "; then if rbenv alias --list | grep --quiet "$app "
then
rbenv alias $app --remove rbenv alias $app --remove
fi fi
@ -164,7 +165,7 @@ ynh_ruby_install() {
_ynh_ruby_cleanup _ynh_ruby_cleanup
# Set environment for Ruby users # Set environment for Ruby users
echo "#rbenv echo "#rbenv
export RBENV_ROOT=$RBENV_INSTALL_DIR export RBENV_ROOT=$RBENV_INSTALL_DIR
export PATH=\"$RBENV_INSTALL_DIR/bin:$PATH\" export PATH=\"$RBENV_INSTALL_DIR/bin:$PATH\"
eval \"\$(rbenv init -)\" eval \"\$(rbenv init -)\"
@ -181,7 +182,7 @@ eval \"\$(rbenv init -)\"
# This helper will also cleanup unused Ruby versions # This helper will also cleanup unused Ruby versions
# #
# usage: ynh_ruby_remove # usage: ynh_ruby_remove
ynh_ruby_remove() { ynh_ruby_remove () {
[[ -n "${ruby_version:-}" ]] || ynh_die "\$ruby_version should be defined prior to calling ynh_ruby_remove" [[ -n "${ruby_version:-}" ]] || ynh_die "\$ruby_version should be defined prior to calling ynh_ruby_remove"
@ -207,29 +208,34 @@ ynh_ruby_remove() {
# This helper will check what Ruby version are no more required, # This helper will check what Ruby version are no more required,
# and uninstall them # and uninstall them
# If no app uses Ruby, rbenv will be also removed. # If no app uses Ruby, rbenv will be also removed.
_ynh_ruby_cleanup() { _ynh_ruby_cleanup () {
# List required Ruby versions # List required Ruby versions
local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$') local installed_apps=$(yunohost app list | grep -oP 'id: \K.*$')
local required_ruby_versions="" local required_ruby_versions=""
for installed_app in $installed_apps; do for installed_app in $installed_apps
do
local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version") local installed_app_ruby_version=$(ynh_app_setting_get --app=$installed_app --key="ruby_version")
if [[ -n "$installed_app_ruby_version" ]]; then if [[ -n "$installed_app_ruby_version" ]]
then
required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}" required_ruby_versions="${installed_app_ruby_version}\n${required_ruby_versions}"
fi fi
done done
# Remove no more needed Ruby versions # Remove no more needed Ruby versions
local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/') local installed_ruby_versions=$(rbenv versions --bare --skip-aliases | grep -Ev '/')
for installed_ruby_version in $installed_ruby_versions; do for installed_ruby_version in $installed_ruby_versions
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"; then do
if ! echo ${required_ruby_versions} | grep -q "${installed_ruby_version}"
then
echo "Removing Ruby-$installed_ruby_version" echo "Removing Ruby-$installed_ruby_version"
$RBENV_INSTALL_DIR/bin/rbenv uninstall --force $installed_ruby_version $RBENV_INSTALL_DIR/bin/rbenv uninstall --force $installed_ruby_version
fi fi
done done
# If none Ruby version is required # If none Ruby version is required
if [[ -z "$required_ruby_versions" ]]; then if [[ -z "$required_ruby_versions" ]]
then
# Remove rbenv environment configuration # Remove rbenv environment configuration
echo "Removing rbenv" echo "Removing rbenv"
ynh_safe_rm "$RBENV_INSTALL_DIR" ynh_safe_rm "$RBENV_INSTALL_DIR"
@ -238,9 +244,9 @@ _ynh_ruby_cleanup() {
} }
_ynh_ruby_try_bash_extension() { _ynh_ruby_try_bash_extension() {
if [ -x src/configure ]; then if [ -x src/configure ]; then
src/configure && make -C src 2>&1 || { src/configure && make -C src 2>&1 || {
ynh_print_info "Optional bash extension failed to build, but things will still work normally." ynh_print_info "Optional bash extension failed to build, but things will still work normally."
} }
fi fi
} }

View file

@ -98,7 +98,7 @@ ynh_app_setting() {
# Trick to only re-enable debugging if it was set before # Trick to only re-enable debugging if it was set before
local xtrace_enable=$(set +o | grep xtrace) local xtrace_enable=$(set +o | grep xtrace)
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
app, action = os.environ['APP'], os.environ['ACTION'].lower() app, action = os.environ['APP'], os.environ['ACTION'].lower()
key, value = os.environ['KEY'], os.environ.get('VALUE', None) key, value = os.environ['KEY'], os.environ.get('VALUE', None)
@ -125,11 +125,15 @@ EOF
# Legacy: auto-convert phpversion to php_version (for consistency with nodejs_version, ruby_version, ...) # Legacy: auto-convert phpversion to php_version (for consistency with nodejs_version, ruby_version, ...)
# This has to be here and not in the "php" code file because ynh_app_setting_set/delete need to be defined @_@ # This has to be here and not in the "php" code file because ynh_app_setting_set/delete need to be defined @_@
if [[ -n "${app:-}" ]] && [[ -n "${phpversion:-}" ]]; then if [[ -n "${app:-}" ]] && [[ -n "${phpversion:-}" ]]
if [[ -z "${php_version:-}" ]]; then then
if [[ -z "${php_version:-}" ]]
then
php_version=$phpversion php_version=$phpversion
ynh_app_setting_set --key=php_version --value=$php_version ynh_app_setting_set --key=php_version --value=$php_version
fi fi
ynh_app_setting_delete --key=phpversion ynh_app_setting_delete --key=phpversion
unset phpversion unset phpversion
fi fi

View file

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

View file

@ -18,7 +18,7 @@ ynh_string_random() {
filter=${filter:-'A-Za-z0-9'} filter=${filter:-'A-Za-z0-9'}
# =========================================== # ===========================================
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \ dd if=/dev/urandom bs=1 count=1000 2>/dev/null \
| tr --complement --delete "$filter" \ | tr --complement --delete "$filter" \
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p' | sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
} }

View file

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

View file

@ -12,7 +12,7 @@ ynh_system_user_exists() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
getent passwd "$username" &> /dev/null getent passwd "$username" &>/dev/null
} }
# Check if a group exists on the system # Check if a group exists on the system
@ -27,7 +27,7 @@ ynh_system_group_exists() {
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
# =========================================== # ===========================================
getent group "$group" &> /dev/null getent group "$group" &>/dev/null
} }
# Create a system user # Create a system user

View file

@ -29,7 +29,7 @@
# This option is meant for advanced use-cases where the "simple" templating # This option is meant for advanced use-cases where the "simple" templating
# mode ain't enough because you need conditional blocks or loops. # mode ain't enough because you need conditional blocks or loops.
# #
# For a full documentation of jinja's syntax you can refer to: # For a full documentation of jinja's syntax you can refer to:
# https://jinja.palletsprojects.com/en/3.1.x/templates/ # https://jinja.palletsprojects.com/en/3.1.x/templates/
# #
# Note that in YunoHost context, all variables are from shell variables and therefore are strings # Note that in YunoHost context, all variables are from shell variables and therefore are strings
@ -70,9 +70,10 @@ ynh_config_add() {
chmod 640 $destination chmod 640 $destination
_ynh_apply_default_permissions $destination _ynh_apply_default_permissions $destination
if [[ "$jinja" == 1 ]]; then if [[ "$jinja" == 1 ]]
then
# This is ran in a subshell such that the "export" does not "contaminate" the main process # This is ran in a subshell such that the "export" does not "contaminate" the main process
( (
export $(compgen -v) export $(compgen -v)
j2 "$template_path" -f env -o $destination j2 "$template_path" -f env -o $destination
) )
@ -215,7 +216,7 @@ ynh_read_var_in_file() {
var_part+='\s*' var_part+='\s*'
# Extract the part after assignation sign # 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)" 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 if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x set -o xtrace # set -x
echo YNH_NULL echo YNH_NULL
@ -291,7 +292,7 @@ ynh_write_var_in_file() {
var_part+='\s*' var_part+='\s*'
# Extract the part after assignation sign # Extract the part after assignation sign
local expression_with_comment="$( (tail +$after_line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)" local expression_with_comment="$((tail +$after_line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL) | head -n1)"
if [[ "$expression_with_comment" == "YNH_NULL" ]]; then if [[ "$expression_with_comment" == "YNH_NULL" ]]; then
set -o xtrace # set -x set -o xtrace # set -x
return 1 return 1

View file

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

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}/data/xmpp"
ynh_backup /var/lib/metronome "${backup_dir}/var_lib_metronome"
ynh_backup /var/xmpp-upload/ "${backup_dir}/var_xmpp-upload"

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