From 1c8341823231e946419812f1ce73a1662fed94b8 Mon Sep 17 00:00:00 2001 From: edrikk Date: Mon, 24 Feb 2025 20:06:22 -0500 Subject: [PATCH 1/4] Custom notifications fix As provided by star-glider in issue: https://github.com/nutechsoftware/alarmdecoder-webapp/issues/99 The custom notification option is broken; the notify_data dictionary is always empty. There's quite a bit of code that works over this dictionary (lines 1182 through 1204 in types.py), but none of it runs because custom_values is blank. I haven't dug in deeply enough to really understand what's going on here; it's way more code than exists in the other notification methods, and I'm not sure why. I ran into this trying to set up Slack notifications (JSON POST) and threw in a quick patch to get it working. Basically, I just skip over all of the inactive code, create a dictionary directly in a manner similar to the other notification methods, and then reference that in the _do_post method call. Since the project isn't being maintained, I don't think it's worth the time to submit a pull request (and do the associated work to figure out why there's all that additional code), but I figured I'd drop my patch in here just in case it helps anyone. Two notes: 1) the modification to line 1144 was just me troubleshooting; it's not relevant to the fix but is kind of a nice-to-have; 2) the new "message_string" variable includes a version of the "Subject" option from the email notification, but I just harcoded in the message instead of modifying the web forms to offer it as a front-end-selectable option, mainly because I'm lazy. Presumably, if you're applying this patch, you can just type in whatever you want there or just set it equal to the 'text' variable to eliminate it entirely. I know the project is essentially abandoned, but it's a great addition to these old (and very reliable) ADEMCO systems. As long as you're running it behind a firewall with no ports exposed, there's really not much risk in running an old image with so little attack surface, and while old it works just perfectly (kind of like my 20-year-old alarm system)! --- ad2web/notifications/types.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ad2web/notifications/types.py b/ad2web/notifications/types.py index 6d6be62..232b653 100644 --- a/ad2web/notifications/types.py +++ b/ad2web/notifications/types.py @@ -1141,7 +1141,7 @@ def _do_post(self, data, app=None): return True else: app.logger.info('Event Custom Notification Failed') - raise Exception('Custom Notification Failed (' + str(http_response.status) + ") " + http_response.reason) + raise Exception('Custom Notification Failed (' + str(http_response.status) + ") " + http_response.reason + " Headers:" + str(self.headers) + " Body:" + str(data)) # Warning: Threaded so it may be sent later and state may change. # Never access any AD2* state vars in a threaded function. @@ -1175,6 +1175,8 @@ def _do_get(self, data, app=None): @raise_with_stack def send(self, type, text, raw): self.msg_to_send = text + message_string = 'Primary Residence Alarm Event: %s' % text + json_data = {"text": message_string} result = False if check_time_restriction(self.starttime, self.endtime): @@ -1211,7 +1213,7 @@ def send(self, type, text, raw): result = self._do_post(self._dict_to_xml('notification', notify_data)) if self.post_type == JSON: - result = self._do_post(self._dict_to_json(notify_data) ) + result = self._do_post(self._dict_to_json(json_data)) if self.method == CUSTOM_METHOD_GET_TYPE: if self.post_type == URLENCODE: From 15586ac6b3eef097d38bf3e4a0756d208d2f6c2a Mon Sep 17 00:00:00 2001 From: edrikk Date: Mon, 24 Feb 2025 20:12:05 -0500 Subject: [PATCH 2/4] Fix: Socket IO ACL not setup. Keypad not working. stuck in Please Wait Loading From jimmyhchan https://github.com/nutechsoftware/alarmdecoder-webapp/issues/93 I have manually setup an raspbian image on a raspberrypi 3 and have most of everything working with a customized version of the docker file. Unfortunately, the virtual keypad was not working. The symptoms is the same as outlined here https://www.alarmdecoder.com/forums/viewtopic.php?f=3&t=1167&p=4267&hilit=keypad+loading#p4267 Steps to repro: setup the webapp go through the setup flow navigate to the keypad page BUG: Keypad only shows Please Wait Loading... Clicks on any button causes the log ERROR: default_error_handler: method_access_denied, You do not have access to method "on_keypress" (endpoint=/alarmdecoder, msg_id=None) [in /usr/local/lib/python2.7/dist-packages/socketio/virtsocket.py:51] Root cause I debugged a bit and found the root cause is user_id is None in the recv_connect method which calls add_acl_method: https://github.com/nutechsoftware/alarmdecoder-webapp/blob/master/ad2web/decoder.py#L829 I could not find anything which sets the user_id for the session. Perhaps a dependency api changed. Fix/workaround I have a fix using user_is_authenticated(current_user) instead. Happy to create a real PR if someone can confirm this is the desired approach. --- ad2web/decoder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ad2web/decoder.py b/ad2web/decoder.py index 3412d9d..9d13834 100644 --- a/ad2web/decoder.py +++ b/ad2web/decoder.py @@ -23,6 +23,7 @@ from sqlalchemy.orm.exc import NoResultFound from flask import Blueprint, Response, request, g, current_app +from flask_login import current_user import jsonpickle from OpenSSL import SSL @@ -826,7 +827,7 @@ def recv_connect(self): # check setup complete setup_stage = Setting.get_by_name('setup_stage').value - if (setup_stage and setup_stage != SETUP_COMPLETE) or user_id: + if (setup_stage and setup_stage != SETUP_COMPLETE) or user_is_authenticated(current_user): self.add_acl_method('on_keypress') self.add_acl_method('on_firmwareupload') self.add_acl_method('on_test') From c80b5c63846ace7622c0bb3033efd931628a5478 Mon Sep 17 00:00:00 2001 From: edrikk Date: Mon, 24 Feb 2025 20:14:44 -0500 Subject: [PATCH 3/4] Update to support Flask-login v0.5.0 Changed 'user_id' to '_user_id' to support changes in Flask-login 0.5.0 - requires requirements.txt update to Flask-login == 0.5.0 --- ad2web/decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ad2web/decoder.py b/ad2web/decoder.py index 9d13834..db70832 100644 --- a/ad2web/decoder.py +++ b/ad2web/decoder.py @@ -822,7 +822,7 @@ def recv_connect(self): session_interface = self._alarmdecoder.app.session_interface session = session_interface.open_session(self._alarmdecoder.app, self._request) - user_id = session.get('user_id', None) + user_id = session.get('_user_id', None) # check setup complete setup_stage = Setting.get_by_name('setup_stage').value From bab1724c6a428a9e005f746d9fcd4e9b0186dcfe Mon Sep 17 00:00:00 2001 From: edrikk Date: Mon, 24 Feb 2025 20:18:56 -0500 Subject: [PATCH 4/4] Update requirements.txt Update the latest compatible version of most modules. --- requirements.txt | 99 ++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/requirements.txt b/requirements.txt index a95d569..df28901 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,55 +1,56 @@ -Babel>=1.3 -Flask>=1.0.0.0 -Flask-Babel>=0.9 -flask-caching>=1.7.2 -Flask-Login>=0.2.10 -Flask-Mail>=0.9.0 -Flask-OpenID>=1.2.1 -Flask-SQLAlchemy>=1.0 -Flask-Script>=0.6.7 -Flask-Testing>=0.4.1 -Flask-WTF>=0.9.4 -Jinja2>=2.7.2 -Mako>=0.9.1 -MarkupSafe>=0.19 -Pygments>=1.6 -SQLAlchemy>=0.9.3 -Sphinx>=1.2.2,<2 -WTForms>=1.0.5 -Werkzeug>=0.9.4 -alarmdecoder>=1.13.4 -alembic>=0.6.4 +Babel==2.9.1 +Flask==1.1.4 +Flask-Babel==1.0.0 +Flask-Caching==1.7.2 +Flask-Login==0.5.0 +Flask-Mail==0.9.1 +Flask-OpenID==1.2.5 +Flask-SQLAlchemy==2.5.1 +Flask-Script==2.0.6 +Flask-Testing==0.8.1 +Flask-WTF==0.14.3 +Jinja2==2.11.3 +Mako>=1.0.7 +MarkupSafe==1.1.1 +Pygments==2.5.2 +SQLAlchemy==1.2.19 +Sphinx==1.8.6 +WTForms==2.2.1 +Werkzeug==0.16.1 +alarmdecoder>=1.13.12 +alembic==1.3.3 argparse>=1.2.1 -async>=0.6.1 -blinker>=1.3 -cffi>=0.8.2 -cryptography>=0.4 +async==0.6.2 +blinker==1.4 +cffi==1.15.1 +pyftdi==0.13.4 +cryptography==3.3.2 distribute>=0.6.24 -docutils>=0.11 +docutils==0.14 gevent==1.1b4 -gevent-socketio>=0.3.6 -gevent-websocket>=0.9.3 -gitdb>=0.5.4 -greenlet>=0.4.2 -itsdangerous>=0.23 -jsonpickle>=0.7.0 -mock>=1.0.1 -nose>=1.3.1 -psutil>=2.0.0 -pyOpenSSL>=0.14 -pycparser>=2.10 -python-openid>=2.2.5 -pytz>=2014.1 -sh>=1.09 -six>=1.6.1 -sleekxmpp>=1.2.4 -smmap>=0.8.2 +gevent-socketio==0.3.6 +gevent-websocket==0.10.1 +gitdb==0.6.4 +greenlet==0.4.15 +itsdangerous==1.1.0 +jsonpickle==0.9.5 +mock==3.0.5 +nose==1.3.7 +psutil==6.1.1 +pyOpenSSL==21.0.0 +pycparser==2.19 +python-openid==2.2.5 +pytz>=2025.1 +sh==1.14.3 +six==1.17.0 +sleekxmpp==1.3.3 +smmap==0.9.0 speaklater>=1.3 wsgiref>=0.1.2 -netifaces>=0.10.4 +netifaces==0.10.4 futures; python_version=="2.7" -numpy>=1.9.2 -chump>=1.5.1 -twilio>=6.8.2 -gntp>=1.0.2 -miniupnpc>=1.9 +numpy==1.16.2 +chump==1.6.0 +twilio==6.63.2 +gntp==1.0.3 +miniupnpc==2.0.2