Commit graph

109 commits

Author SHA1 Message Date
Georg Lauterbach 7721a48b9b
scripts: refactoring & miscellaneous small changes (#2499)
* `update-check.sh` now uses the new log

* refactored `setup-stack.sh`

The changes are:

1. Replaced `""` wiht `''` where possible (reasoning: Bash is very
   implicit and I'd like to use `''` where possible to indicate no
   variables are expanded here)
2. `> /file` -> `>/file` according to our style guide
3. Some log adjustments for messages where I deemed it appropriate
4. Then, an error message from a Dovecot setup was also prevented (by
   adding a check whether the directory is present before a `: >...`
   command would create a file in this directory).

These are all small, miscellaneous changes that I wanted to combine into
one commit and ultimately one PR because I see no point in opening a PR
for every small change here. I hope this is fine.

* added a small `sleep` to the `_shutdown` function

This ensure the last log message is actually logged before Supervisor
logs the message that it received a SIGTERM. This makes reading the log
easier because now the causal relationship is shown (we are terminating
Supervisor, and not someone else and we're just logging it).

I forgot to replace `""` with `''` in `update-check.sh`, so I included
it here because this is the last commit before PR review.

* re-add exit on successful update (only)

* re-added date information to update-check log messages

* added `_log_with_date` function

The new function will log a message with a proper timestamp. This is all
handled in `log.sh`, we therefore not need to source other files too.

This will be used in the future by `check-for-changes.sh` as well :)

Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2022-03-26 10:17:08 +01:00
Georg Lauterbach b9dbec3276
scripts: refactored scripts located under target/bin/ (#2500)
* refactored scripts located under `target/bin/`

The scripts under `target/bin/` now use the new log and I replaced some
`""` with `''` on the way. The functionality stays the same, this mostly
style and log.

* corrected fail2ban (script and tests)

* corrected OpenDKIM log output in tests

* reverted (some) changes to `sedfile`

Moreover, a few messages for BATS were streamlined and a regression in
the linting script reverted.

* apple PR feedback

* improve log output from `fail2ban` script

The new output has a single, clear message with the '[  ERROR  ]  '
prefix, and then output that explains the error afterwards. This is
coherent with the logging style which should be used while providing
more information than just a single line about IPTables not functioning.

* simplified `setquota` script

* consistently named the `__usage` function

Before, scripts located under `target/bin/` were using `usage` or
`__usage`. Now, they're using `__usage` as they should.

* improved `sedfile`

With `sedfile`, we cannot use the helper functions in a nice way because
it is used early in the Dockerfile at a stage where the helper scripts
are not yet copied. The script has been adjusted to be canonical with
all the other scripts under `target/bin/`.

* fixed tests

* removed `__usage` from places where it does not belong

`__usage` is to be used on wrong user input, not on other failures as
well. This was fixed in `delquota` and `setquota`.

* apply PR review feedback
2022-03-26 09:30:09 +01:00
Georg Lauterbach b7bf40ac21
renamed function _errex -> _exit_with_error (#2497) 2022-03-21 15:01:07 +01:00
Casper 37c8e44566
Restart supervisord early (#2494) 2022-03-21 13:42:12 +01:00
Georg Lauterbach 24031ae365
scripts: new log (#2493)
* added new `_log` function

With `_log`, the `_notify` method wa rendered obsolete. `_notify` was
not completely removed due to test failures in `check-for-changes.sh`.

The new `_log` function properly uses log levels such as `trace`,
`debug`, `info`, `warn` and `error`. It provides a cleaner solution
and renders `DMS_DEBUG` obsolete too (as only `_notify` depends on it).

* converted all helper script to new `_log` function

* converted all startup stacks to new `log` function

* `start-mailserver.sh` now uses new `_log` function

* final test and misc small script adjustments

* updated documentation
2022-03-21 07:07:52 +01:00
Casper 1bfc6d944a
Use FQDN as REPORT_SENDER default value. (#2487) 2022-03-18 19:41:02 +01:00
Georg Lauterbach 321ae744fa
scripts: small refactorings (#2485)
Co-authored-by: Casper <casperklein@users.noreply.github.com>
2022-03-17 11:24:30 +01:00
NorseGaud 1ab8ea96b2
acme_extract -> acme_extract.py + F_BIN to avoid .py 2022-03-06 22:17:29 -05:00
Georg Lauterbach d101d0aa0a
fix: remove SA reload for KAM (#2456)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2022-03-04 23:38:29 +01:00
Casper b9fdb1e7b5
Introduce CLAMAV_MESSAGE_SIZE_LIMIT env (#2453) 2022-03-03 16:17:01 +01:00
Casper a8a8c859dc
Rename config examples directory (#2438) 2022-03-02 22:54:14 +00:00
Georg Lauterbach e6af5a118f
Adjust envrionment variables - more sensible defaults (#2428)
The new setup will now set env variables on one place and on one place
only. The old setup used two separate places wich is not DRY and
confusing.

Some default values changed:

1. PFLOGSUMM_TRIGGER: logrotate => none
2. REPORT_SENDER: mailserver-report@HOSTNAME => mailserver-report@DOMAIN
3. REPORT_RECIPIENT: "0" => POSTMASTER_ADDRESS

One env variable was renamed: REPORT_INTERVAL => LOGROTATE_INTERVAL

I believe these defaults to be more sensible, especially the REPORT_RECIPIENT
address. The PFLOGSUMM_TRIGGER value was changed to `none` because otherwise
people would start getting daily Postfix log summary reports automatically.
Now, this is opt-in, and reports are sent only when enabled properly.

Some of the variables changed were marked as deprecated. I removed the note,
as the variables now bear some (sane) defaults again for other variables
(i.e.) REPORT_RECIPIENT is now default for other recipient addresses.

Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
Co-authored-by: Casper <casperklein@users.noreply.github.com>
2022-03-03 10:22:17 +13:00
Casper 57c52d7b5b
PERMIT_DOCKER=none as new default value (#2424)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2022-03-02 16:03:40 +01:00
Georg Lauterbach 399284c092
fix: do not add accounts that already exists to account files (#2419)
Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2022-02-21 13:31:03 +01:00
Georg Lauterbach b61dfe1e24
refactoring: split helper functions into smaller scripts (#2420) 2022-02-21 11:56:57 +01:00
Georg Lauterbach 2927cc47c7
Add SpamAssassin KAM (#2418) 2022-02-21 10:48:28 +01:00
Georg Lauterbach ec8b99335e
Add changedetector functionality for ${SSL_TYPE} == manual (#2404)
Now, setups that use `SSL_TYPE=manual` will profit from the changedetector as well. Certificate changes are picked up and properly propagated.
2022-02-18 11:29:51 +01:00
Christian Raue 908e95fa74
consistently make 1 the default value for SPAMASSASSIN_SPAM_TO_INBOX (#2361)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2022-02-17 09:31:45 +01:00
Georg Lauterbach ce9e86c462
fix: double occurence of /etc/postfix/regexp (#2397) 2022-02-12 09:20:45 +13:00
Philipp Fruck 4c3af32692
Rootless Podman security update (#2393)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Co-authored-by: Casper <casperklein@users.noreply.github.com>
2022-02-09 10:25:09 +01:00
Georg Lauterbach ede2b2394a
improvement: get rid of subshell + exec in helper-functions.sh (#2401)
* get rid of subshell + exec

The new way of executing `sha512sum` should work as well as the old way
but without the clutter and possible problems the usage of subshells +
exec incurs.

Moreover, there was a misconception about array expansion. Using `""`
around an expanding array (`${ARRAY[@]}`) is quite fine (and actually
the preffered way), not because it makes the expansion _one_ string
(this would be `${ARRAY[*]}`), but it makes sure when elements are
expanded, each element has `""` around them so to speak, i.e. there is
no re-splitting of these elements.

* removed old concerns in comments

* increase test and check for changes sleep duration
2022-02-09 11:21:45 +13:00
Christian Raue da17e8bf0b
add env var LOGWATCH_SENDER (#2362)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2022-01-10 12:29:11 +01:00
Casper 29c2d975ec
Fix harmless startup errors (#2357) 2022-01-08 00:25:09 +01:00
Casper 0c31f71358
Introduce DOVECOT_INET_PROTOCOLS env (#2358) 2022-01-06 00:53:18 +01:00
Casper 9d5a9a16a0
Introduce ENABLE_DNSBL env (#2342)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2022-01-03 22:03:46 +01:00
Casper f7465a5088
Prevent race condition on supervisorctl reload (#2343)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-12-29 17:36:29 +01:00
Casper d46e094280
Remove quotes to meet style guidelines (#2330)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-12-21 17:01:40 +01:00
Georg Lauterbach 99cc9fec2a
Updated ShellCheck to 0.8.0 and Hadolint to 2.8.0 (#2329)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2021-12-19 11:56:22 +01:00
Brennan Kinney 6d06149581
fix: Restore detection of letsencrypt certificate file changes (#2326)
The `DYNAMIC_FILES` var was quote wrapped, treating all filepaths to create checksums for as a single string that would be ignored instead of processed individually.

Removed the quotes, and changed the for loop to an array which accomplishes the same goal.


* fix: Prevent unnecessary change detection event

`acme.json` change would extract new cert files, which would then be hashed after restarting services and considered a change event, running through the logic again and restarting services once more when that was not required.

The checksum entries for those cert files are now replaced with new entries containing updated checksum hashes, after `acme.json` extraction.
2021-12-19 11:25:15 +13:00
Georg Lauterbach a4095a7d48
Disable service stats for Dovecot explicitly (#2292)
Co-authored-by: Casper <casperklein@users.noreply.github.com>

Co-authored-by: Casper <casperklein@users.noreply.github.com>
2021-12-12 12:08:34 +01:00
Casper a8a39a0a1a
Rename function and adjust comment (#2306) 2021-11-28 17:02:07 +01:00
Brennan Kinney 5254f7c658
fix: check-for-changes.sh should not fall out of sync with shared logic (#2260)
Removes duplicate logic from `check-for-changes.sh` that is used/maintained elsewhere to avoid risk of problems, as this code is already starting to diverge / rot.

---

Previously the change detection support has had code added for rebuilding config upon change detection which is the same as code run during startup scripts. Unfortunately over time this has fallen out of sync. Mostly the startup scripts would get maintenance and the contributor and reviewers may not have been aware of the duplicate code handled by `check-for-changes.sh`.

That code was starting to diverge in addition to some changes in structure (_eg: relay host logic seems interleaved here vs separated out in startup scripts_). I wanted to address this before it risks becoming a much bigger headache.

Rather than bloat `helper-functions.sh` further, I've added a `helpers/` folder extracting relevant common logic between startup scripts and `changedetector`. If you want to follow that process I've kept scoped commits to make those diffs easier. Some minor changes/improvements were added but nothing significant.

---

- chore: Extract relay host logic to new `relay.sh` helper
- chore: Extract `/etc/postfix/sasl_passwd` logic to new `sasl.sh` helper
- chore: Extract `postfix-accounts.cf` logic to new `accounts.sh` helper
- chore: Extract `/etc/aliases` logic to new `aliases.sh` helper
- chore: Extract `/etc/postfix/vhost` logic to new `postfix.sh` helper

- chore: Add inline docs for Postfix configs
> These are possibly more verbose than needed and can be reduced at a later stage.
> They are helpful during this refactor process while investigating that everything is handled correctly.

`accounts.sh`: 
- Add note regarding potential bug for bare domain setups with `/etc/postfix/vhost` and `mydestination` sharing same domain value.

`relay.sh`: 
- Remove the tabs for a single space delimiter, revised associated comment.
- Add PR reference for original `_populate_relayhost_map` implementation which has some useful details.


Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Co-authored-by: Casper <casperklein@users.noreply.github.com>
2021-11-21 09:33:49 +13:00
Georg Lauterbach ae70142d8f
Housekeeping (#2302)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2021-11-20 10:38:40 +01:00
Brennan Kinney 7ca056852f
tests(feat): Complete rewrite of letsencrypt tests (#2286)
* chore: Normalize container setup

Easier to grok what is different between configurations.

- Container name usage replaced with variable
- Volumes defined earlier and redeclared when relevant (only real difference is `VOLUME_LETSENCRYPT`)
- Contextual comment about the `acme.json` copy.
- Quoting `SSL_TYPE`, `SSL_DOMAIN` and `-h` values for syntax highlighting.
- Moved `-t` and `${NAME}` to separate line.
- Consistent indentation.

* chore: DRY test logic

Extracts out repeated test logic into methods

* chore: Scope configs to individual test cases (1/3)

- Preparation step for shifting out the container configs to their own scoped test cases. Split into multiple commits to ease reviewing by diffs for this change.
- Re-arrange the hostname and domain configs to match the expected order of the new test cases.
- Shuffle the hostname and domainname grouped tests into tests per container config scope.
- Collapse the `acme.json` test cases into single test case.

* chore: Scope configs to individual test cases (2/3)

- Shifts the hostname and domainname container configs into their respective scoped test cases.
- Moving the `acme.json` container config produces a less favorable diff, so is deferred to a follow-up commit.
- Test cases updated to refer to their `${CONTAINER_NAME}` var instead of the hard-coded string name.

* chore: Scope configs to individual test cases (3/3)

Final commit to shift out the container configs.

- Common vars are exported in `setup_file()` for the test cases to use without needing to repeat the declaration in each test case.
- `teardown_file()` shifts container removal at end of scoped test case.

* chore: Adapt to `common_container_setup` template

- `CONTAINER_NAME` becomes `TEST_NAME` (`common.bash` helper via `init_with_defaults`).
- `docker run ...` and related configuration is now outsourced to the `common.bash` helper, only extra args that the default template does not cover are defined in the test case.
- `TARGET_DOMAIN`establishes the domain folder name for `/etc/letsencrypt/live`.
- `_should*` methods no longer manage a `CONTAINER_NAME` arg, instead using the `TEST_NAME` global that should be valid as test is run as a sequence of test cases.
- `PRIVATE_CONFIG` and the `private_config_path ...` are now using the global `TEST_TMP_CONFIG` initialized at the start of each test case, slightly different as not locally defined/scoped like `PRIVATE_CONFIG` would be within the test case, hence the explicit choice of a different name for context.

* chore: Minor tweaks

- Test case comment descriptions.
- DRY: `docker rm -f` lines moved to `teardown()`
- Use `wait_for_service` helper instead of checking the `changedetector` script itself is running.
- There is a startup delay before the `changedetector` begins monitoring, wait until it ready event is logged.
- Added a helper to query logs for a service (useful later).
- `/bin/sh` commands reduced to `sh`.
- Change the config check to match and compare output, not number of lines returned. Provides better failure output by bats to debug against.

* chore: Add more test functions for `acme.json`

This just extracts out existing logic from the test case to functions to make the test case itself more readable/terse.

* chore: Housekeeping

No changes, just moving logic around and grouping into inline functions, with some added comments.

* chore: Switch to `example.test` certs

This also required copying the source files to match the expected letsencrypt file structure expected in the test/container usage.

* chore: Delete `test/config/letsencrypt/`

No longer necessary, using the `example.test/` certs instead.

These letsencrypt certs weren't for the domains they were used for, and of course long expired.

* chore: Housekeeping

Add more maintainer comments, rename some functions.

* tests: Expand `acme.json` extraction coverage

Finally able to add more test coverage! :)

- Two new methods to validate expected success/failure of extraction for a given FQDN.
- Added an RSA test prior to the wildcard to test a renewal simulation (just with different cert type).
- Added extra method to make sure we're detecting multiple successful change events, not just a previous logged success (false positive).

* tests: Refactor the negotiate_tls functionality

Covers all ports (except POP) and correctly tests against expected verification status with new `example.test` certs.

The `FQDN` var will be put to use in a follow-up commit.

* tests: Verify the certs contain the expected FQDNs

* chore: Extract TLS test methods into a separate helper script

Can be useful for other TLS tests to utilize.

* chore: Housekeeping

* chore: Fix test typo

There was a mismatch between the output and expected output between these two files "find key for" and "find key & cert for". Changed to "find key and/or cert for" to make the warning more clear that it's issued for either or both failure conditions.

Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-11-16 16:00:16 +01:00
Brennan Kinney 584577787a
refactor: Internal HOSTNAME and DOMAINNAME configuration (#2280)
Better logical flow, handling and inline documentation.

Despite the verbosity, it's better to make this visible here for maintenance and debugging purposes than trying to dig through issue/PR or commit history for it.

* fix: Panic when HOSTNAME is misconfigured
* chore: Add more comment docs for maintainers
* tests(fix): Use `--domainname` not ENV `DOMAINNAME`

Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-11-16 10:50:45 +13:00
Casper cac0647250
improve: sort environment variables (#2298) 2021-11-14 09:11:44 +13:00
Georg Lauterbach 6c1c669619
make Bash start user-patches.sh (#2295) 2021-11-13 10:19:56 +01:00
Georg Lauterbach cf4682fe5e
remove unnecessary ls from debug log (#2294) 2021-11-12 14:33:04 +01:00
Andreas Egli e436968655
openDMARC: remove quotation marks from setup script (#2291) 2021-11-10 12:21:26 +01:00
Brennan Kinney 917f0f6a9c
fix: Monitor for changes in supported letsencrypt locations (#2279)
Previously we only monitored for `$HOSTNAME` in `/etc/letsencrypt/live` and only for hard-coded `.pem` filenames.

This ensures we check the locations of other locations that may not match `$HOSTNAME`, which we also support. Ideally in future at least the directory to look in would be better known in advance..
2021-11-05 12:08:57 +13:00
Brennan Kinney e807631a76
refactor: acme.json extraction (#2274)
Split into scoped commits with messages if further details are needed, view those via the associated PR :)

**Commit Summary:**

**`check-for-changes.sh`**

- Prevent `SSL_DOMAIN` silently skipping when value has wildcard prefix `*.` (_at least this was known as a bugfix when originally committed in linked PR_).
- Improved inlined docs for maintainers.
- Additional logging for debugging.

**`helper-functions.sh:_extract_certs_from_acme`**:

- Fail if the input arg (_`$CERT_DOMAIN`, aka the FQDN_) provided for extraction is empty.
- Use `$CERT_DOMAIN` in place of `$HOSTNAME` and `$1` for a consistent value (_previously could mismatch, eg with `SSL_DOMAIN` defined_).
- The conditional is now only for handling extraction failure (_key or cert value is missing from extraction_).
- Log an actual warning or success (debug) based on outcome.
- Don't use `SSL_DOMAIN` with wildcard value for the `mkdir` letsencrypt directory name (_wildcard prefix `*.` is first stripped instead_).

**`acme_extract`** (_new python utility for `acme.json` handling_):

- Extracted out into a python script that can be treated as a utility in the `$PATH` like other helper scripts. It can now be used and optionally tested directly instead of via `helper-functions.sh`.
-Made compatible with Python 3, as Python 2 is EOL and no longer in newer versions of Debian.
2021-11-04 09:28:40 +13:00
Brennan Kinney bdb35dd19a
chore: Refactor setup-stack.sh case SSL_TYPE=letsencrypt (#2278)
Mostly cleans up the code and documents it better, although there are some minor fixes for handling `SSL_DOMAIN` ENV and additional logging added for spotting issues related to it in future when troubleshooting.

Commits are scoped with context messages for easing review if necessary. Overview of changes:

Traefik specific:

- Logic extracted out into it's own function.
- Conditional reworked to assist with debugging.
- `SSL_DOMAIN` must not be empty when attempting to extract.
- Added additional notes.

`SSL_TYPE=letsencrypt` case:

- Revised top note block.
- Correct handling for `SSL_DOMAIN`.
- Removed some unnecessary nesting.
- Less repetitive error message for `LETSENCRYPT_DOMAIN`.
- Added use of panics where appropriate (kept `return 1` so failures still exit functionality early).
- Improved inline docs.
2021-11-03 09:12:33 +13:00
Casper ebb081c80f
Add missing SA variables (#2283) 2021-11-02 11:51:36 +01:00
Casper b117cd1423
Improve VIRUSMAILS_DELETE_DELAY usage (#2281) 2021-11-01 22:13:14 +01:00
Casper c7dec1e330
fix(listmailuser): Don't query quota, if ENABLE_QUOTAS is not 1
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-11-01 12:09:47 +01:00
Georg Lauterbach 537247031f
fix: Make Dovecot aware of basic aliases in userdb for quota support + Use correct hash scheme in passdb configuration (#2248)
Dovecot quota support would log auth failures when Postfix validated incoming mail to accept/reject and the `check_policy_service` for `quota-status` was queried with a recipient that was an account alias.

When Dovecot is not aware of the user account, it will not be able to check a quota and inform Postfix that everything is fine, Postfix will accept the mail and send it to Dovecot, where if the quota is exceeded will result in a bounce back to the sender. This is considered "backscatter" and can be abused by spammers forging the sender address which can get your server blacklisted.

The solution is to either disable quota support `ENABLE_QUOTAS=0`, or as a workaround, add dummy accounts to Dovecot userdb for aliases in `postfix-virtual.cf` (not `postfix-aliases.cf`), these dummy accounts will map to the real user account mailbox (real users are defined in `postfix-accounts.cf`).

The workaround is naive, in that we only check for basic 1-to-1 alias mapping to real accounts. This will still be an issue for aliases that map to another alias or multiple addresses (real or alias). Unfortunately Postfix will not expand aliases until accepting mail where this would be too late.

A better solution is to proxy the `check_policy_service` from Dovecot `quota-status` that Postfix queries in `main.cf:smtpd_recipient_restrictions`, however this requires a fair amount more of additional work and still requires an implementation to recursively query aliases for nested or multiple address mappings, which can then be forwarded to the `quota-status` service configured by Dovecot in `/etc/dovecot/conf.d/90-quota.conf`.

LDAP users are unaffected as quota support is not supported/implemented with `docker-mailserver` at this time, it is always considered disabled when using LDAP.

---

Additionally Dovecot configuration for `passdb` has been fixed to use the correct password hash scheme of `SHA512-CRYPT`. 

Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2021-11-01 14:20:22 +13:00
Brennan Kinney 79617dcc40
fix: ONE_DIR=1 should keep correct permissions for spool-postfix (#2273)
GID of postfix(102) should not be set here. only GID is root(0) and postdrop(103). Ensure root(0) UID matches source location ownership too.
2021-11-01 10:23:00 +13:00
Casper 34ba3c2a5b
Add warnings when Amavis is disabled. (#2251)
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-10-17 16:18:56 +00:00
Casper 61973f731c
Relaxed error handling (#2233) 2021-10-03 12:48:43 +00:00
Casper c7e9dd2bad
function _defunc removed (#2199)
* function _defunc removed

* _shutdown is better than just notify in that cases

* PANIC_TYPE 'fail-init' introduced

Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2021-09-23 19:49:07 +02:00