Skip to content

Commit 38ac6e4

Browse files
mohan43uflashcode
authored andcommitted
weenotifier.py 0.1.0: switched to gotify and ntfy.sh
switched push notification backend from irssinotifier to gotify and ntfy.sh. irssinotifier is no longer maintailed
1 parent e29e776 commit 38ac6e4

File tree

1 file changed

+151
-103
lines changed

1 file changed

+151
-103
lines changed

python/weenotifier.py

Lines changed: 151 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Copyright (c) 2021 The gitlab.com/mohan43u/weenotifier Authors.
1+
"""
2+
Copyright (c) 2021-present Mohan Raman <[email protected]>.
23
34
All rights reserved.
45
@@ -25,146 +26,193 @@
2526
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2627
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2728
28-
20210-07-01: Mohan R
29-
0.0.1: Initial release
29+
2021-07-01: Mohan R
30+
0.0.1: Initial release with IrssiNotifier
31+
(https://irssinotifier.appspot.com/)
32+
33+
2024-10-06: Mohan R
34+
0.1.0: switched to gotify (https://gotify.net/)
35+
it should also support ntfy.sh (https://ntfy.sh)
3036
31-
Description: notifier using IrssiNotifier (https://irssinotifier.appspot.com/)
37+
Description: notifier for push notification
3238
Project URL: https://gitlab.com/mohan43u/weenotifier
3339
"""
3440

35-
import os
36-
import base64
3741
from urllib.parse import urlencode
3842

3943
try:
4044
import weechat
41-
weechat.register('weenotifier',
42-
'Mohan R',
43-
'0.0.1',
44-
'BSD 2-Clause Simplified',
45-
'notifier using \
46-
IrssiNotifier (https://irssinotifier.appspot.com/)',
47-
'shutdown_cb',
48-
'')
49-
except ImportError as exception:
50-
raise ImportError('This script has to run under \
51-
WeeChat (https://weechat.org/)') from exception
52-
53-
54-
try:
55-
from cryptography.hazmat.primitives import hashes, ciphers, padding
45+
result = weechat.register("weenotifier",
46+
"Mohan R",
47+
"0.1.0",
48+
"BSD 2-Clause Simplified",
49+
"notifier for push notification",
50+
"shutdown_cb",
51+
"")
5652
except ImportError as exception:
57-
raise ImportError('failed to import cryptography module \
58-
(https://cryptography.io)') from exception
59-
60-
61-
weenotifier = None
53+
raise ImportError("This script has to run under" +
54+
"WeeChat (https://weechat.org/)") from exception
6255

6356

6457
class WeeNotifier:
65-
"""Weenotifier - primary class."""
58+
"""
59+
Weenotifier - primary class.
60+
"""
6661

6762
def __init__(self):
68-
"""Weenotifier - initialization."""
63+
"""
64+
Weenotifier - initialization.
65+
"""
66+
6967
self.options = {
70-
'url': 'https://irssinotifier.appspot.com/API/Message',
71-
'token': '',
72-
'password': 'password'
68+
"url": "", # gotify: https://selfhostedgotify.yrdomain.tld/message
69+
# ntfy.sh: https://ntfy.sh/youruniquetopic
70+
"token": ""
7371
}
7472

7573
for option, value in self.options.items():
7674
if not weechat.config_is_set_plugin(option):
77-
weechat.config_set_plugin(option, value)
78-
79-
self.url = weechat.config_get_plugin('url')
80-
if self.url is None or len(self.url) <= 0:
81-
raise NameError('weenotifier: url not configured')
82-
83-
self.token = weechat.config_get_plugin('token')
84-
if self.token is None or len(self.token) <= 0:
85-
raise NameError('weenotifier: token not configured')
86-
87-
self.password = weechat.config_get_plugin('password')
88-
if self.password is None or len(self.password) <= 0:
89-
raise NameError('weenotifier: password not configured')
90-
91-
self.version = weechat.info_get('version_number', '') or '0'
92-
weechat.hook_print('', '', '', 1, 'message_cb', '')
93-
94-
def encrypt(self, password, data):
95-
"""Encrypt given data using md5 + salt + aes-128-cbc."""
96-
# IrssiNotifier requires null at the end
97-
databytes = data.encode() + bytes(1)
98-
padder = padding.PKCS7(128).padder()
99-
padded_data = padder.update(databytes) + padder.finalize()
100-
salt = os.urandom(8)
101-
key = None
102-
iv = None
103-
104-
for n in range(2):
105-
# this following logic is similar to EVP_BytesToKey() from openssl
106-
md5hash = hashes.Hash(hashes.MD5())
107-
if key is not None:
108-
md5hash.update(key)
109-
md5hash.update(password.encode())
110-
md5hash.update(salt)
111-
md5 = md5hash.finalize()
112-
if key is None:
113-
key = md5
114-
continue
115-
if iv is None:
116-
iv = md5
117-
118-
aes256cbc = ciphers.Cipher(ciphers.algorithms.AES(key),
119-
ciphers.modes.CBC(iv))
120-
encryptor = aes256cbc.encryptor()
121-
edata = encryptor.update(padded_data) + encryptor.finalize()
122-
edata = 'Salted__'.encode() + salt + edata
123-
edata = base64.b64encode(edata, b'-_')
124-
edata = edata.replace(b'=', b'')
125-
return edata
126-
127-
def message(self, data, buffer, date, tags, isdisplayed, ishighlight,
128-
prefix, message):
129-
"""Send message to IrssiNotifier."""
130-
if int(ishighlight):
131-
channel = weechat.buffer_get_string(buffer, 'sort_name') or \
132-
weechat.buffer_get_string(buffer, 'name')
133-
post = urlencode({'apiToken': self.token,
134-
'channel': self.encrypt(self.password, channel),
135-
'nick': self.encrypt(self.password, prefix),
136-
'message': self.encrypt(self.password, message),
137-
'version': self.version})
138-
weechat.hook_process_hashtable('url:' + self.url,
139-
{'postfields': post}, 10000, '', '')
75+
_ = weechat.config_set_plugin(option,
76+
value)
77+
78+
self.url = weechat.config_get_plugin("url")
79+
if len(self.url) <= 0:
80+
raise NameError("weenotifier: 'url' not configured")
81+
82+
# for gotify
83+
token = weechat.config_get_plugin("token")
84+
if len(token) > 0:
85+
self.url += "?token=" + token
86+
87+
self.version = weechat.info_get("version_number",
88+
"") or "0"
89+
_ = weechat.hook_print("",
90+
"",
91+
"",
92+
1,
93+
"message_cb",
94+
"")
95+
96+
def message(self,
97+
_data: str,
98+
buffer: str,
99+
_date: int,
100+
tags: list[str],
101+
_displayed: int,
102+
highlight: int,
103+
prefix: str,
104+
message: str):
105+
"""
106+
Send message to push notification server.
107+
"""
108+
109+
if highlight or ("notify_private" in tags):
110+
channel = weechat.buffer_get_string(buffer, "short_name") or \
111+
weechat.buffer_get_string(buffer, "name")
112+
message = prefix + ": " + message
113+
post = channel + ": " + message
114+
115+
# format for gotify
116+
if "?token=" in self.url:
117+
post = urlencode({"title": channel,
118+
"message": message,
119+
"priority": "4"})
120+
121+
_ = weechat.hook_process_hashtable("url:" + self.url,
122+
{"post": "1",
123+
"postfields": post},
124+
10000,
125+
"result_cb",
126+
"")
127+
return weechat.WEECHAT_RC_OK
128+
129+
def result(self,
130+
data: str,
131+
url: str,
132+
returncode: int,
133+
output: str,
134+
err: str):
135+
"""
136+
Print result of url request
137+
"""
138+
139+
if returncode != 0 or ("error" in output) or len(err) > 0:
140+
print(url,
141+
data,
142+
returncode,
143+
output,
144+
err)
145+
return weechat.WEECHAT_RC_ERROR
140146
return weechat.WEECHAT_RC_OK
141147

142148
def shutdown(self):
143-
"""Shutdown callback."""
149+
"""
150+
Shutdown
151+
"""
152+
153+
print("shutdown invoked")
144154
return weechat.WEECHAT_RC_OK
145155

146156

147-
def message_cb(data, buffer, date, tags, isdisplayed, ishighlight, prefix,
148-
message):
149-
"""Message callback Which will be called by weechat-C-api."""
157+
weenotifier: WeeNotifier | None = None
158+
159+
160+
def message_cb(data: str,
161+
buffer: str,
162+
date: int,
163+
tags: list[str],
164+
displayed: int,
165+
highlight: int,
166+
prefix: str,
167+
message: str):
168+
"""
169+
Message callback by weechat-C-api.
170+
"""
171+
172+
if weenotifier is not None:
173+
return weenotifier.message(data,
174+
buffer,
175+
date,
176+
tags,
177+
displayed,
178+
highlight,
179+
prefix,
180+
message)
181+
return weechat.WEECHAT_RC_ERROR
182+
183+
184+
def result_cb(data: str,
185+
url: str,
186+
returncode: int,
187+
output: str,
188+
err: str):
189+
"""
190+
Result callback by weechat-C-api
191+
"""
192+
150193
if weenotifier is not None:
151-
return weenotifier.message(data, buffer, date, tags, isdisplayed,
152-
ishighlight, prefix, message)
194+
return weenotifier.result(data,
195+
url,
196+
returncode,
197+
output,
198+
err)
153199
return weechat.WEECHAT_RC_ERROR
154200

155201

156202
def shutdown_cb():
157-
"""Shutdown callback Which will be called by weechat-C-api."""
203+
"""
204+
Shutdown callback by weechat-C-api
205+
"""
206+
158207
if weenotifier is not None:
159208
return weenotifier.shutdown()
160209
return weechat.WEECHAT_RC_ERROR
161210

162211

163212
def main():
164-
"""Start point."""
165213
global weenotifier
166214
weenotifier = WeeNotifier()
167215

168216

169-
if __name__ == '__main__':
217+
if __name__ == "__main__":
170218
main()

0 commit comments

Comments
 (0)