From 7a9c17928a736be78fa0a9a2745dc91f38a386ab Mon Sep 17 00:00:00 2001 From: Gavin Chappell Date: Sun, 3 Jul 2022 21:50:21 +0100 Subject: [PATCH] add support for basic auth on self-hosted instances --- borgmatic/config/schema.yaml | 12 ++++++++++++ borgmatic/hooks/ntfy.py | 9 +++++++++ docs/how-to/monitor-your-backups.md | 6 ++++++ tests/unit/hooks/test_ntfy.py | 20 ++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 02caf7929..ad50d253a 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -916,6 +916,18 @@ properties: description: | The address of your self-hosted ntfy.sh instance. example: https://ntfy.your-domain.com + username: + type: string + description: | + The username for your self-hosted ntfy.sh instance + (ignored for the upstream-hosted instance) + example: borgmatic + password: + type: string + description: | + The password for your self-hosted ntfy.sh instance. + (ignored for the upstream-hosted instance) + example: superSecretP@ssw0rd start: type: object properties: diff --git a/borgmatic/hooks/ntfy.py b/borgmatic/hooks/ntfy.py index c62b51103..570b25aec 100644 --- a/borgmatic/hooks/ntfy.py +++ b/borgmatic/hooks/ntfy.py @@ -56,6 +56,15 @@ def ping_monitor(hook_config, config_filename, state, monitoring_log_level, dry_ 'X-Tags': state_config.get('tags'), } + if ( + base_url != 'https://ntfy.sh' + and hook_config.get('username') is not None + and hook_config.get('password') is not None + ): + headers.update( + {'Authorization': f'{hook_config.get("username")}:{hook_config.get("password")}'} + ) + if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) try: diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 3dabb7de2..2660c7350 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -286,6 +286,10 @@ so the default messages are intentionally generic. These can be overridden, depe on your risk assessment. Each `state` can have its own custom messages, priorities and tags or, if none are provided, will use the default. +A [self-hosted ntfy instance](https://ntfy.sh/docs/install/) can be used if desired, +including support for Basic Authentication using the `username` and `password` fields +with a custom `server` value + An example configuration is shown here, with all the available options, including [priorities](https://ntfy.sh/docs/publish/#message-priority) and [tags](https://ntfy.sh/docs/publish/#tags-emojis): @@ -295,6 +299,8 @@ hooks: ntfy: topic: my-unique-topic server: https://ntfy.my-domain.com + username: borgmatic + password: superSecretP@ssw0rd start: title: A Borgmatic backup started message: Watch this space... diff --git a/tests/unit/hooks/test_ntfy.py b/tests/unit/hooks/test_ntfy.py index 3867cee1d..685363365 100644 --- a/tests/unit/hooks/test_ntfy.py +++ b/tests/unit/hooks/test_ntfy.py @@ -155,3 +155,23 @@ def test_ping_monitor_with_other_error_logs_warning(): monitoring_log_level=1, dry_run=False, ) + + +def test_ping_monitor_minimal_config_hits_selfhosted_with_custom_auth(): + hook_config = { + 'topic': topic, + 'server': custom_base_url, + 'username': 'unittesting', + 'password': 'dummypassword', + } + expected_headers = { + **return_default_message_headers(module.monitor.State.FAIL), + 'Authorization': 'unittesting:dummypassword', + } + flexmock(module.requests).should_receive('post').with_args( + f'{custom_base_url}/{topic}', headers=expected_headers, + ).and_return(flexmock(ok=True)).once() + + module.ping_monitor( + hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + )