mirror of
https://github.com/caronc/apprise-api.git
synced 2025-01-06 14:09:33 +01:00
APPRISE_ALLOW_SERVICES and APPRISE_DENY_SERVICES globals added (#64)
This commit is contained in:
parent
efe88a52d3
commit
2943bce981
@ -197,6 +197,9 @@ The use of environment variables allow you to provide over-rides to default sett
|
||||
| `APPRISE_STATELESS_URLS` | For a non-persistent solution, you can take advantage of this global variable. Use this to define a default set of Apprise URLs to notify when using API calls to `/notify`. If no `{KEY}` is defined when calling `/notify` then the URLs defined here are used instead. By default, nothing is defined for this variable.
|
||||
| `APPRISE_STATEFUL_MODE` | This can be set to the following possible modes:<br/>📌 **hash**: This is also the default. It stores the server configuration in a hash formatted that can be easily indexed and compressed.<br/>📌 **simple**: Configuration is written straight to disk using the `{KEY}.cfg` (if `TEXT` based) and `{KEY}.yml` (if `YAML` based).<br/>📌 **disabled**: Straight up deny any read/write queries to the servers stateful store. Effectively turn off the Apprise Stateful feature completely.
|
||||
| `APPRISE_CONFIG_LOCK` | Locks down your API hosting so that you can no longer delete/update/access stateful information. Your configuration is still referenced when stateful calls are made to `/notify`. The idea of this switch is to allow someone to set their (Apprise) configuration up and then as an added security tactic, they may choose to lock their configuration down (in a read-only state). Those who use the Apprise CLI tool may still do it, however the `--config` (`-c`) switch will not successfully reference this access point anymore. You can however use the `apprise://` plugin without any problem ([see here for more details](https://github.com/caronc/apprise/wiki/Notify_apprise_api)). This defaults to `no` and can however be set to `yes` by simply defining the global variable as such.
|
||||
| `APPRISE_DENY_SERVICES` | A comma separated set of entries identifying what plugins to deny access to. You only need to identify one schema entry associated with a plugin to in turn disable all of it. Hence, if you wanted to disable the `glib` plugin, you do not need to additionally include `qt` as well since it's included as part of the (`dbus`) package; consequently specifying `qt` would in turn disable the `glib` module as well (another way to acomplish the same task). To exclude/disable more the one upstream service, simply specify additional entries separated by a `,` (comma) or ` ` (space). The `APPRISE_DENY_SERVICES` entries are ignored if the `APPRISE_ALLOW_SERVICES` is identified. By default, this is initialized to `windows, dbus, gnome, macos, syslog` (blocking local actions from being issued inside of the docker container)
|
||||
| `APPRISE_ALLOW_SERVICES` | A comma separated set of entries identifying what plugins to allow access to. You may only use alpha-numeric characters as is the restriction of Apprise Schemas (schema://) anyway. To exclusivly include more the one upstream service, simply specify additional entries separated by a `,` (comma) or ` ` (space). The `APPRISE_DENY_SERVICES` entries are ignored if the `APPRISE_ALLOW_SERVICES` is identified.
|
||||
|
||||
| `SECRET_KEY` | A Django variable acting as a *salt* for most things that require security. This API uses it for the hash sequences when writing the configuration files to disk (`hash` mode only).
|
||||
| `ALLOWED_HOSTS` | A list of strings representing the host/domain names that this API can serve. This is a security measure to prevent HTTP Host header attacks, which are possible even under many seemingly-safe web server configurations. By default this is set to `*` allowing any host. Use space to delimit more than one host.
|
||||
| `BASE_URL` | Those who are hosting the API behind a proxy that requires a subpath to gain access to this API should specify this path here as well. By default this is not set at all.
|
||||
|
@ -41,7 +41,7 @@ class GetTests(SimpleTestCase):
|
||||
"""
|
||||
|
||||
# our key to use
|
||||
key = 'test_get_config'
|
||||
key = 'test_get_config_'
|
||||
|
||||
# GET returns 405 (not allowed)
|
||||
response = self.client.get('/get/{}'.format(key))
|
||||
@ -49,7 +49,7 @@ class GetTests(SimpleTestCase):
|
||||
|
||||
# No content saved to the location yet
|
||||
response = self.client.post('/get/{}'.format(key))
|
||||
assert response.status_code == 204
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
# Add some content
|
||||
response = self.client.post(
|
||||
|
@ -54,7 +54,7 @@ class JsonUrlsTests(SimpleTestCase):
|
||||
|
||||
# Nothing to return
|
||||
response = self.client.get('/json/urls/{}'.format(key))
|
||||
assert response.status_code == 204
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
# Add some content
|
||||
response = self.client.post(
|
||||
|
@ -22,7 +22,7 @@
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
from django.test import SimpleTestCase
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from unittest.mock import patch
|
||||
from ..forms import NotifyForm
|
||||
import json
|
||||
@ -342,3 +342,153 @@ class NotifyTests(SimpleTestCase):
|
||||
assert response.status_code == 200
|
||||
assert mock_notify.call_count == 1
|
||||
assert response['content-type'] == 'text/html'
|
||||
|
||||
@patch('apprise.plugins.NotifyEmail.send')
|
||||
def test_notify_with_filters(self, mock_send):
|
||||
"""
|
||||
Test workings of APPRISE_DENY_SERVICES and APPRISE_ALLOW_SERVICES
|
||||
"""
|
||||
|
||||
# Set our return value
|
||||
mock_send.return_value = True
|
||||
|
||||
# our key to use
|
||||
key = 'test_notify_with_restrictions'
|
||||
|
||||
# Add some content
|
||||
response = self.client.post(
|
||||
'/add/{}'.format(key),
|
||||
{'urls': 'mailto://user:pass@yahoo.ca'})
|
||||
assert response.status_code == 200
|
||||
|
||||
# Preare our JSON data
|
||||
json_data = {
|
||||
'body': 'test notifiction',
|
||||
'type': apprise.NotifyType.WARNING,
|
||||
}
|
||||
|
||||
# Verify by default email is enabled
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is True
|
||||
|
||||
# Send our service with the `mailto://` denied
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES="mailto"):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# mailto:// is disabled
|
||||
assert response.status_code == 424
|
||||
assert mock_send.call_count == 0
|
||||
|
||||
# What actually took place behind close doors:
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is False
|
||||
|
||||
# Reset our flag (for next test)
|
||||
apprise.plugins.SCHEMA_MAP['mailto'].enabled = True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `mailto://` denied
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES="invalid, syslog"):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# mailto:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify that mailto was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `mailto://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="mailto"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# mailto:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify email was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `mailto://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="invalid, mailtos"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# mailto:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify email was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `mailto://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="syslog"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# mailto:// is disabled
|
||||
assert response.status_code == 424
|
||||
assert mock_send.call_count == 0
|
||||
|
||||
# What actually took place behind close doors:
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is False
|
||||
|
||||
# Reset our flag (for next test)
|
||||
apprise.plugins.SCHEMA_MAP['mailto'].enabled = True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Test case where there is simply no over-rides defined
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify/{}'.format(key),
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is disabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# nothing was changed
|
||||
assert apprise.plugins.SCHEMA_MAP['mailto'].enabled is True
|
||||
|
@ -89,6 +89,9 @@ class StatelessNotifyTests(SimpleTestCase):
|
||||
Test sending multiple notifications where one fails
|
||||
"""
|
||||
|
||||
# Ensure we're enabled for the purpose of our testing
|
||||
apprise.plugins.SCHEMA_MAP['mailto'].enabled = True
|
||||
|
||||
# Set our return value; first we return a true, then we fail
|
||||
# on the second call
|
||||
mock_notify.side_effect = (True, False)
|
||||
@ -110,7 +113,7 @@ class StatelessNotifyTests(SimpleTestCase):
|
||||
assert response.status_code == 424
|
||||
assert mock_notify.call_count == 2
|
||||
|
||||
@override_settings(APPRISE_STATELESS_URLS="windows://")
|
||||
@override_settings(APPRISE_STATELESS_URLS="mailto://user:pass@localhost")
|
||||
@patch('apprise.Apprise.notify')
|
||||
def test_notify_default_urls(self, mock_notify):
|
||||
"""
|
||||
@ -249,3 +252,152 @@ class StatelessNotifyTests(SimpleTestCase):
|
||||
# Still supported
|
||||
assert response.status_code == 400
|
||||
assert mock_notify.call_count == 0
|
||||
|
||||
@patch('apprise.plugins.NotifyJSON.send')
|
||||
def test_notify_with_filters(self, mock_send):
|
||||
"""
|
||||
Test workings of APPRISE_DENY_SERVICES and APPRISE_ALLOW_SERVICES
|
||||
"""
|
||||
|
||||
# Set our return value
|
||||
mock_send.return_value = True
|
||||
|
||||
# Preare our JSON data
|
||||
json_data = {
|
||||
'urls': 'json://user:pass@yahoo.ca',
|
||||
'body': 'test notifiction',
|
||||
'type': apprise.NotifyType.WARNING,
|
||||
}
|
||||
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# Ensure we're enabled for the purpose of our testing
|
||||
apprise.plugins.SCHEMA_MAP['json'].enabled = True
|
||||
|
||||
# Send our service with the `json://` denied
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES="json"):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is disabled
|
||||
assert response.status_code == 204
|
||||
assert mock_send.call_count == 0
|
||||
|
||||
# What actually took place behind close doors:
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is False
|
||||
|
||||
# Reset our flag (for next test)
|
||||
apprise.plugins.SCHEMA_MAP['json'].enabled = True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `json://` denied
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES="invalid, syslog"):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify that json was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `json://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="json"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify email was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `json://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="invalid, jsons"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is enabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# Verify email was never turned off
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send our service with the `json://` being the only accepted type
|
||||
with override_settings(APPRISE_ALLOW_SERVICES="syslog"):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is disabled
|
||||
assert response.status_code == 204
|
||||
assert mock_send.call_count == 0
|
||||
|
||||
# What actually took place behind close doors:
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is False
|
||||
|
||||
# Reset our flag (for next test)
|
||||
apprise.plugins.SCHEMA_MAP['json'].enabled = True
|
||||
|
||||
# Reset Mock
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Test case where there is simply no over-rides defined
|
||||
with override_settings(APPRISE_ALLOW_SERVICES=""):
|
||||
with override_settings(APPRISE_DENY_SERVICES=""):
|
||||
# Send our notification as a JSON object
|
||||
response = self.client.post(
|
||||
'/notify',
|
||||
data=json.dumps(json_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
# json:// is disabled
|
||||
assert response.status_code == 200
|
||||
assert mock_send.call_count == 1
|
||||
|
||||
# nothing was changed
|
||||
assert apprise.plugins.SCHEMA_MAP['json'].enabled is True
|
||||
|
@ -46,6 +46,12 @@ import apprise
|
||||
import json
|
||||
import re
|
||||
|
||||
# import the logging library
|
||||
import logging
|
||||
|
||||
# Get an instance of a logger
|
||||
logger = logging.getLogger('django')
|
||||
|
||||
# Content-Type Parsing
|
||||
# application/x-www-form-urlencoded
|
||||
# application/x-www-form-urlencoded
|
||||
@ -560,6 +566,63 @@ class NotifyView(View):
|
||||
status=status,
|
||||
)
|
||||
|
||||
#
|
||||
# Apply Any Global Filters (if identified)
|
||||
#
|
||||
if settings.APPRISE_ALLOW_SERVICES:
|
||||
alphanum_re = re.compile(
|
||||
r'^(?P<name>[a-z][a-z0-9]+)', re.IGNORECASE)
|
||||
entries = \
|
||||
[alphanum_re.match(x).group('name').lower()
|
||||
for x in re.split(r'[ ,]+', settings.APPRISE_ALLOW_SERVICES)
|
||||
if alphanum_re.match(x)]
|
||||
|
||||
for plugin in set(apprise.plugins.SCHEMA_MAP.values()):
|
||||
if entries:
|
||||
# Get a list of the current schema's associated with
|
||||
# a given plugin
|
||||
schemas = set(apprise.plugins.details(plugin)
|
||||
['tokens']['schema']['values'])
|
||||
|
||||
# Check what was defined and see if there is a hit
|
||||
for entry in entries:
|
||||
if entry in schemas:
|
||||
# We had a hit; we're done
|
||||
break
|
||||
|
||||
if entry in schemas:
|
||||
entries.remove(entry)
|
||||
# We can keep this plugin enabled and move along to the
|
||||
# next one...
|
||||
continue
|
||||
|
||||
# if we reach here, we have to block our plugin
|
||||
plugin.enabled = False
|
||||
|
||||
for entry in entries:
|
||||
# Generate some noise for those who have bad configurations
|
||||
logger.warning(
|
||||
'APPRISE_ALLOW_SERVICES plugin %s:// was not found - '
|
||||
'ignoring.', entry)
|
||||
|
||||
elif settings.APPRISE_DENY_SERVICES:
|
||||
alphanum_re = re.compile(
|
||||
r'^(?P<name>[a-z][a-z0-9]+)', re.IGNORECASE)
|
||||
entries = \
|
||||
[alphanum_re.match(x).group('name').lower()
|
||||
for x in re.split(r'[ ,]+', settings.APPRISE_DENY_SERVICES)
|
||||
if alphanum_re.match(x)]
|
||||
|
||||
for name in entries:
|
||||
try:
|
||||
# Force plugin to be disabled
|
||||
apprise.plugins.SCHEMA_MAP[name].enabled = False
|
||||
|
||||
except KeyError:
|
||||
logger.warning(
|
||||
'APPRISE_DENY_SERVICES plugin %s:// was not found -'
|
||||
' ignoring.', name)
|
||||
|
||||
# Prepare ourselves a default Asset
|
||||
asset = None if not body_format else \
|
||||
apprise.AppriseAsset(body_format=body_format)
|
||||
@ -648,7 +711,7 @@ class NotifyView(View):
|
||||
# the response to a 424 error code
|
||||
msg = _('One or more notification could not be sent.')
|
||||
status = ResponseCode.failed_dependency
|
||||
return HttpResponse(msg, status=status) \
|
||||
return HttpResponse(response if response else msg, status=status) \
|
||||
if not json_response else JsonResponse({
|
||||
'error': msg,
|
||||
},
|
||||
@ -726,6 +789,63 @@ class StatelessNotifyView(View):
|
||||
asset = None if not body_format else \
|
||||
apprise.AppriseAsset(body_format=body_format)
|
||||
|
||||
#
|
||||
# Apply Any Global Filters (if identified)
|
||||
#
|
||||
if settings.APPRISE_ALLOW_SERVICES:
|
||||
alphanum_re = re.compile(
|
||||
r'^(?P<name>[a-z][a-z0-9]+)', re.IGNORECASE)
|
||||
entries = \
|
||||
[alphanum_re.match(x).group('name').lower()
|
||||
for x in re.split(r'[ ,]+', settings.APPRISE_ALLOW_SERVICES)
|
||||
if alphanum_re.match(x)]
|
||||
|
||||
for plugin in set(apprise.plugins.SCHEMA_MAP.values()):
|
||||
if entries:
|
||||
# Get a list of the current schema's associated with
|
||||
# a given plugin
|
||||
schemas = set(apprise.plugins.details(plugin)
|
||||
['tokens']['schema']['values'])
|
||||
|
||||
# Check what was defined and see if there is a hit
|
||||
for entry in entries:
|
||||
if entry in schemas:
|
||||
# We had a hit; we're done
|
||||
break
|
||||
|
||||
if entry in schemas:
|
||||
entries.remove(entry)
|
||||
# We can keep this plugin enabled and move along to the
|
||||
# next one...
|
||||
continue
|
||||
|
||||
# if we reach here, we have to block our plugin
|
||||
plugin.enabled = False
|
||||
|
||||
for entry in entries:
|
||||
# Generate some noise for those who have bad configurations
|
||||
logger.warning(
|
||||
'APPRISE_ALLOW_SERVICES plugin %s:// was not found - '
|
||||
'ignoring.', entry)
|
||||
|
||||
elif settings.APPRISE_DENY_SERVICES:
|
||||
alphanum_re = re.compile(
|
||||
r'^(?P<name>[a-z][a-z0-9]+)', re.IGNORECASE)
|
||||
entries = \
|
||||
[alphanum_re.match(x).group('name').lower()
|
||||
for x in re.split(r'[ ,]+', settings.APPRISE_DENY_SERVICES)
|
||||
if alphanum_re.match(x)]
|
||||
|
||||
for name in entries:
|
||||
try:
|
||||
# Force plugin to be disabled
|
||||
apprise.plugins.SCHEMA_MAP[name].enabled = False
|
||||
|
||||
except KeyError:
|
||||
logger.warning(
|
||||
'APPRISE_DENY_SERVICES plugin %s:// was not found -'
|
||||
' ignoring.', name)
|
||||
|
||||
# Prepare our apprise object
|
||||
a_obj = apprise.Apprise(asset=asset)
|
||||
|
||||
|
@ -150,3 +150,16 @@ APPRISE_STATELESS_URLS = os.environ.get('APPRISE_STATELESS_URLS', '')
|
||||
# - simple: content is just written straight to disk 'as-is'
|
||||
# - disabled: disable all stateful functionality
|
||||
APPRISE_STATEFUL_MODE = os.environ.get('APPRISE_STATEFUL_MODE', 'hash')
|
||||
|
||||
# Our Apprise Deny List
|
||||
# - By default we disable all non-remote calling servicess
|
||||
# - You do not need to identify every schema supported by the service you
|
||||
# wish to disable (only one). For example, if you were to specify
|
||||
# xml, that would include the xmls entry as well (or vs versa)
|
||||
APPRISE_DENY_SERVICES = os.environ.get('APPRISE_DENY_SERVICES', ','.join((
|
||||
'windows', 'dbus', 'gnome', 'macosx', 'syslog')))
|
||||
|
||||
# Our Apprise Exclusive Allow List
|
||||
# - anything not identified here is denied/disabled)
|
||||
# - this list trumps the APPRISE_DENY_SERVICES identified above
|
||||
APPRISE_ALLOW_SERVICES = os.environ.get('APPRISE_ALLOW_SERVICES', '')
|
||||
|
@ -1,6 +1,6 @@
|
||||
django
|
||||
cryptography == 3.3.2
|
||||
apprise == 0.9.5.1
|
||||
apprise == 0.9.6
|
||||
|
||||
# 3rd party service support
|
||||
slixmpp
|
||||
|
Loading…
Reference in New Issue
Block a user