Python : Set OMEMO as an optional dependency;

SVG    : Add a selection of variations of the Slixfeed logo.
This commit is contained in:
Schimon Jehudah, Adv. 2024-09-11 09:48:27 +03:00
parent 3913f740ef
commit 178f49cb86
13 changed files with 408 additions and 135 deletions

View file

@ -57,9 +57,20 @@ It is possible to install Slixfeed using pip and pipx.
```
$ python3 -m venv .venv
$ source .venv/bin/activate
```
##### Install
```
$ pip install git+https://git.xmpp-it.net/sch/Slixfeed
```
##### Install (OMEMO)
```
$ pip install git+https://git.xmpp-it.net/sch/Slixfeed[omemo]
```
#### pipx
##### Install

View file

@ -37,33 +37,36 @@ keywords = [
"xml",
"xmpp",
]
# urls = {Homepage = "https://gitgud.io/sjehuda/slixfeed"}
dependencies = [
"aiofiles",
"aiohttp",
# "daemonize",
"feedparser",
"lxml",
"omemo", # OMEMO
# "pysocks",
"protobuf==3.20.3", # OMEMO
"python-dateutil",
"requests",
"slixmpp",
"slixmpp-omemo", # OMEMO
"tomli", # Python 3.10
"tomli_w",
"X3DH", # OMEMO
"XEdDSA", # OMEMO
]
[project.urls]
Homepage = "http://slixfeed.i2p/"
Repository = "https://gitgud.io/sjehuda/slixfeed"
Homepage = "https://slixfeed.woodpeckersnest.space"
Repository = "https://git.xmpp-it.net/sch/Slixfeed"
Issues = "https://gitgud.io/sjehuda/slixfeed/issues"
[project.optional-dependencies]
omemo = [
"DoubleRatchet>=0.7.0,<0.8",
"OMEMO>=0.13.0,<0.15",
"protobuf==3.20.3",
"slixmpp-omemo",
"X3DH>=0.5.9,<0.6",
"XEdDSA<0.5,>=0.4.7",
]
proxy = ["pysocks"]
# [project.readme]

View file

@ -28,9 +28,9 @@ Good luck!
filetypes = "Atom, JSON, RDF, RSS, XML."
platforms = "XMPP"
# platforms = "ActivityPub, Briar, DeltaChat, Email, IRC, LXMF, MQTT, Nostr, Session, Tox."
# platforms = "ActivityPub, BitMessage, Briar, DeltaChat, Email, IRC, LXMF, MQTT, Nostr, Session, Tox."
comment = "For ideal experience, we recommend using XMPP." # Nostr, Session or DeltaChat
url = "https://gitgud.io/sjehuda/slixfeed"
url = "https://git.xmpp-it.net/sch/Slixfeed"
[[about]]
name = "slixmpp"
@ -260,7 +260,7 @@ Slixfeed is distributed in the hope that it will be useful, but WITHOUT ANY \
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR \
A PARTICULAR PURPOSE. See the MIT License for more details.
"""]
link = "https://gitgud.io/sjehuda/slixfeed"
link = "https://git.xmpp-it.net/sch/Slixfeed"
[[license]]
title = "License"

View file

@ -1 +1,48 @@
<svg height="600" width="600" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0zm0 0" style="fill:#ffa000" transform="translate(44 44)"/><path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279zm0 0" style="fill:#ffa000" transform="translate(44 44)"/><path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47Zm0 0" style="fill:#ffa000" transform="translate(44 44)"/></svg>
<svg height="600" width="600" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feFlood flood-color="rgba(0,0,0,0.5)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Glass Gradient -->
<linearGradient id="glassGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.3); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(255, 255, 255, 0.1); stop-opacity:1" />
</linearGradient>
</defs>
<!-- Black shapes with orange margins -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:#ffa000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:#ffa000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:#ffa000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<!-- Glass Shadow Effect Layer -->
<g filter="url(#shadow)">
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,48 @@
<svg height="600" width="600" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feFlood flood-color="rgba(0,0,0,0.5)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Glass Gradient -->
<linearGradient id="glassGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.3); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(255, 255, 255, 0.1); stop-opacity:1" />
</linearGradient>
</defs>
<!-- Black shapes with orange margins -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:#000000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:#000000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:#000000; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<!-- Glass Shadow Effect Layer -->
<g filter="url(#shadow)">
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,51 @@
<svg height="600" width="600" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<defs>
<!-- Gradient for Glass Effect -->
<linearGradient id="glassGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.5); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(0, 0, 0, 0.2); stop-opacity:1" />
</linearGradient>
<linearGradient id="glassHighlight" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.8); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(255, 255, 255, 0); stop-opacity:1" />
</linearGradient>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feFlood flood-color="rgba(0, 0, 0, 0.3)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<!-- Shapes with Glass Effect -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<!-- Highlights for Shiny Effect -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassHighlight); opacity:0.6;"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassHighlight); opacity:0.6;"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassHighlight); opacity:0.6;"
transform="translate(44 44)" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,48 @@
<svg height="600" width="600" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feFlood flood-color="rgba(0,0,0,0.5)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Glass Gradient -->
<linearGradient id="glassGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.3); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(255, 255, 255, 0.1); stop-opacity:1" />
</linearGradient>
</defs>
<!-- Black shapes with orange margins -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<!-- Glass Shadow Effect Layer -->
<g filter="url(#shadow)">
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,48 @@
<svg height="600" width="600" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feFlood flood-color="rgba(0,0,0,0.5)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Glass Gradient -->
<linearGradient id="glassGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgba(255, 255, 255, 0.3); stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(255, 255, 255, 0.1); stop-opacity:1" />
</linearGradient>
</defs>
<!-- Black shapes with orange margins -->
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:#ffffff; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:#ffffff; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:#ffffff; stroke:#e15a00; stroke-width:10; filter:url(#shadow);"
transform="translate(44 44)" />
<!-- Glass Shadow Effect Layer -->
<g filter="url(#shadow)">
<path d="M167 406a60 60 0 1 1-120 0 60 60 0 0 1 120 0z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 186v80c110 0 199 89 199 199h80c0-154-125-279-279-279z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
<path d="M47 47v79c187 0 338 152 338 339h80C465 234 277 47 47 47z"
style="fill:url(#glassGradient); stroke:none;"
transform="translate(44 44)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -3032,7 +3032,7 @@ def check_entry_exist(db_file, feed_id, identifier=None, title=None, link=None,
"""
SELECT id
FROM entries_properties
WHERE identifier = :identifier and feed_id = :feed_id
WHERE identifier = :identifier AND feed_id = :feed_id
"""
)
par = {

View file

@ -1,2 +1,2 @@
__version__ = '0.1.94'
__version_info__ = (0, 1, 94)
__version__ = '0.1.95'
__version_info__ = (0, 1, 95)

View file

@ -36,7 +36,6 @@ import slixfeed.sqlite as sqlite
from slixfeed.syndication import FeedTask
from slixfeed.utilities import Documentation, Html, MD, Task, Url
from slixfeed.xmpp.commands import XmppCommands
from slixfeed.xmpp.encryption import XmppOmemo
from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.presence import XmppPresence
from slixfeed.xmpp.status import XmppStatusTask
@ -48,6 +47,10 @@ import sys
import time
from typing import Optional
try:
from slixfeed.xmpp.encryption import XmppOmemo
except Exception as e:
print('Encryption of type OMEMO is not enabled. Reason: ' + str(e))
logger = Logger(__name__)
@ -150,7 +153,7 @@ class XmppChat:
# await compose.message(self, jid_bare, message)
if self['xep_0384'].is_encrypted(message):
if self.omemo_present and self['xep_0384'].is_encrypted(message):
allow_untrusted=True # Temporary fix. This should be handled by "retry""
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
self, message, allow_untrusted)
@ -229,8 +232,8 @@ class XmppChat:
case _ if command_lowercase in ['greetings', 'hallo', 'hello',
'hey', 'hi', 'hola', 'holla',
'hollo']:
response = ('Greeting! My name is {}.\n'
'I am an RSS News Bot.\n'
response = ('Greeting. My name is {}.\n'
'I am an Atom/RSS News Bot.\n'
'Send "help" for further instructions.\n'
.format(self.alias))
case _ if command_lowercase.startswith('add'):
@ -358,7 +361,7 @@ class XmppChat:
# XmppMessage.send_oob_reply_message(message, url, response)
if url:
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if encrypted:
if self.omemo_present and encrypted:
url_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, message_from, url)
XmppMessage.send_omemo_oob(self, message_from, url_encrypted, chat_type)
@ -591,7 +594,7 @@ class XmppChat:
response = XmppCommands.search_items(db_file, query)
case 'start':
status_type = 'available'
status_message = '📫️ Welcome back!'
status_message = '📫️ Welcome back.'
XmppPresence.send(self, jid_bare, status_message,
status_type=status_type)
await asyncio.sleep(5)
@ -627,7 +630,7 @@ class XmppChat:
if response:
encrypt_omemo = Config.get_setting_value(self, jid_bare, 'omemo')
encrypted = True if encrypt_omemo else False
if encrypted and self['xep_0384'].is_encrypted(message):
if self.omemo_present and encrypted and self['xep_0384'].is_encrypted(message):
response_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, message_from, response)
if omemo_decrypted and omemo_encrypted:
@ -732,17 +735,17 @@ class XmppChatAction:
media_url = None
if media_url and news_digest:
if encrypt_omemo:
if self.omemo_present and encrypt_omemo:
news_digest_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, news_digest)
if encrypt_omemo and omemo_encrypted:
if self.omemo_present and encrypt_omemo and omemo_encrypted:
XmppMessage.send_omemo(self, jid, chat_type, news_digest_encrypted)
else:
# Send textual message
XmppMessage.send(self, jid_bare, news_digest, chat_type)
news_digest = ''
# Send media
if encrypt_omemo:
if self.omemo_present and encrypt_omemo:
cache_dir = config.get_default_cache_directory()
# if not media_url.startswith('data:'):
filename = media_url.split('/').pop().split('?')[0]
@ -796,9 +799,10 @@ class XmppChatAction:
media_url = None
if news_digest:
if encrypt_omemo: news_digest_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, news_digest)
if encrypt_omemo and omemo_encrypted:
if self.omemo_present and encrypt_omemo:
news_digest_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, news_digest)
if self.omemo_present and encrypt_omemo and omemo_encrypted:
XmppMessage.send_omemo(self, jid, chat_type, news_digest_encrypted)
else:
XmppMessage.send(self, jid_bare, news_digest, chat_type)
@ -959,4 +963,4 @@ class XmppChatTask:
.format(jid_bare))
logger.info('Starting tasks "interval" for JID {}'.format(jid_bare))
self.task_manager[jid_bare]['interval'] = asyncio.create_task(
XmppChatTask.task_message(self, jid_bare))
XmppChatTask.task_message(self, jid_bare))

View file

@ -54,7 +54,6 @@ from slixfeed.version import __version__
from slixfeed.xmpp.bookmark import XmppBookmark
from slixfeed.xmpp.chat import XmppChat, XmppChatTask
from slixfeed.xmpp.connect import XmppConnect, XmppConnectTask
from slixfeed.xmpp.encryption import XmppOmemo
from slixfeed.xmpp.groupchat import XmppGroupchat
from slixfeed.xmpp.ipc import XmppIpcServer
from slixfeed.xmpp.iq import XmppIQ
@ -69,8 +68,6 @@ from slixfeed.xmpp.status import XmppStatusTask
from slixfeed.xmpp.upload import XmppUpload
from slixfeed.xmpp.utilities import XmppUtilities
from slixmpp import JID
import slixmpp_omemo
from slixmpp_omemo import PluginCouldNotLoad
import sys
import time
@ -154,21 +151,32 @@ class XmppClient(slixmpp.ClientXMPP):
self.register_plugin('xep_0363') # HTTP File Upload
self.register_plugin('xep_0402') # PEP Native Bookmarks
self.register_plugin('xep_0444') # Message Reactions
try:
self.register_plugin(
'xep_0384',
{
'data_dir': Data.get_pathname_to_omemo_directory(),
},
module=slixmpp_omemo,) # OMEMO Encryption
except (PluginCouldNotLoad,):
logger.error('An error has occured when loading the OMEMO plugin.')
sys.exit(1)
try:
self.register_plugin('xep_0454')
except slixmpp.plugins.base.PluginNotFound:
logger.error('Could not load xep_0454. Ensure you have '
'\'cryptography\' from extras_require installed.')
from slixfeed.xmpp.encryption import XmppOmemo
import slixmpp_omemo
from slixmpp_omemo import PluginCouldNotLoad
self.omemo_present = True
except Exception as e:
print('Encryption of type OMEMO is not enabled. Reason: ' + str(e))
self.omemo_present = False
if self.omemo_present:
try:
self.register_plugin(
'xep_0384',
{
'data_dir': Data.get_pathname_to_omemo_directory(),
},
module=slixmpp_omemo,) # OMEMO Encryption
except (PluginCouldNotLoad,):
logger.error('An error has occured when loading the OMEMO plugin.')
sys.exit(1)
try:
self.register_plugin('xep_0454')
except slixmpp.plugins.base.PluginNotFound:
logger.error('Could not load xep_0454. Ensure you have '
'\'cryptography\' from extras_require installed.')
# proxy_enabled = config.get_value('accounts', 'XMPP', 'proxy_enabled')
# if proxy_enabled == '1':
@ -868,7 +876,7 @@ class XmppClient(slixmpp.ClientXMPP):
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'PubSub')
form['instructions'] = 'Publish news items to PubSub nodes.'
options = form.add_field(desc='From which medium source do you '
@ -889,16 +897,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['prev'] = None
session['payload'] = form
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -909,7 +917,7 @@ class XmppClient(slixmpp.ClientXMPP):
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
values = payload['values']
form = self['xep_0004'].make_form('form', 'Publish')
form['instructions'] = ('Choose a PubSub Jabber ID and verify '
@ -997,16 +1005,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['has_next'] = True
session['prev'] = self._handle_publish
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -1413,13 +1421,14 @@ class XmppClient(slixmpp.ClientXMPP):
return session
async def _handle_filters(self, iq, session):
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
jid = session['from'].bare
db_file = config.get_pathname_to_database(jid_bare)
form = self['xep_0004'].make_form('form', 'Filters')
@ -1458,16 +1467,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['next'] = self._handle_filters_complete
session['payload'] = form
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -1522,13 +1531,14 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_add(self, iq, session):
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'Subscribe')
# form['instructions'] = 'Add a new custom subscription.'
form.add_field(desc='Enter a URL.',
@ -1570,16 +1580,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['prev'] = None
session['payload'] = form
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -2036,13 +2046,14 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_discover(self, iq, session):
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'Discover & Search')
form['instructions'] = 'Discover news subscriptions of all kinds'
options = form.add_field(desc='Select type of search.',
@ -2059,16 +2070,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['payload'] = form
session['prev'] = None
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -2160,13 +2171,14 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscriptions(self, iq, session):
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'Subscriptions')
form['instructions'] = ('Browse, view, toggle or remove '
'tags and subscriptions.')
@ -2210,16 +2222,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['next'] = self._handle_subscriptions_result
session['has_next'] = True
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -2520,13 +2532,13 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_advanced(self, iq, session):
jid_full = session['from'].full
jid = session['from']
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
logger.debug('{}: jid: {}'
.format(function_name, jid))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'Advanced')
form['instructions'] = 'Extended options'
options = form.add_field(ftype='list-single',
@ -2547,16 +2559,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['next'] = self._handle_advanced_result
session['prev'] = self._handle_advanced
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -2940,6 +2952,7 @@ class XmppClient(slixmpp.ClientXMPP):
# TODO Attempt to look up for feeds of hostname of JID (i.e. scan
# jabber.de for feeds for juliet@jabber.de)
async def _handle_promoted(self, iq, session):
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
@ -2947,7 +2960,7 @@ class XmppClient(slixmpp.ClientXMPP):
jid_bare = session['from'].bare
jid_full = session['from'].full
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
form = self['xep_0004'].make_form('form', 'Subscribe')
# NOTE Refresh button would be of use
form['instructions'] = 'Featured subscriptions'
@ -2998,16 +3011,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['payload'] = form
session['prev'] = self._handle_promoted
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session
@ -3646,13 +3659,14 @@ class XmppClient(slixmpp.ClientXMPP):
session. Additional, custom data may be saved
here to persist across handler callbacks.
"""
jid = session['from']
jid_full = session['from'].full
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}'
.format(function_name, jid_full))
jid_bare = session['from'].bare
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
if XmppUtilities.is_access(self, jid, chat_type):
db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file)
@ -3750,16 +3764,16 @@ class XmppClient(slixmpp.ClientXMPP):
session['next'] = self._handle_settings_complete
session['payload'] = form
else:
if not XmppUtilities.is_operator(self, jid_bare):
if chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
elif not XmppUtilities.is_operator(self, jid_bare):
text_warn = 'This resource is restricted to operators.'
elif chat_type == 'groupchat':
text_warn = ('This resource is restricted to moderators of {}.'
.format(jid_bare))
elif chat_type == 'error':
text_warn = ('Could not determine chat type of {}.'
.format(jid_bare))
else:
text_warn = 'This resource is forbidden.'
text_warn = 'This resource is restricted.'
session['notes'] = [['warn', text_warn]]
return session

View file

@ -9,10 +9,8 @@ logger = Logger(__name__)
# class XmppChat
# class XmppUtility:
class XmppUtilities:
async def get_chat_type(self, jid):
"""
Check chat (i.e. JID) type.
@ -60,21 +58,18 @@ class XmppUtilities:
return result
def is_access(self, jid_bare, jid_full, chat_type):
def is_access(self, jid, chat_type):
"""Determine access privilege"""
operator = XmppUtilities.is_operator(self, jid_bare)
if operator:
if chat_type == 'groupchat':
if XmppUtilities.is_moderator(self, jid_bare, jid_full):
access = True
else:
access = True
room = jid_bare = jid.bare
alias = jid.resource
if chat_type == 'groupchat':
access = True if XmppUtilities.is_moderator(self, room, alias) else False
if access: print('Access granted to groupchat moderator ' + alias)
else:
access = False
print('Access granted to chat ' + jid_bare)
access = True
return access
def is_operator(self, jid_bare):
"""Check if given JID is an operator"""
result = False
@ -84,25 +79,29 @@ class XmppUtilities:
# operator_name = operator['name']
break
return result
def is_moderator(self, jid_bare, jid_full):
"""Check if given JID is a moderator"""
alias = jid_full[jid_full.index('/')+1:]
role = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'role')
if role == 'moderator':
result = True
else:
result = False
def is_admin(self, room, alias):
"""Check if given JID is an administrator"""
affiliation = self.plugin['xep_0045'].get_jid_property(room, alias, 'affiliation')
result = True if affiliation == 'admin' else False
return result
def is_owner(self, room, alias):
"""Check if given JID is an owner"""
affiliation = self.plugin['xep_0045'].get_jid_property(room, alias, 'affiliation')
result = True if affiliation == 'owner' else False
return result
def is_moderator(self, room, alias):
"""Check if given JID is a moderator"""
role = self.plugin['xep_0045'].get_jid_property(room, alias, 'role')
result = True if role == 'moderator' else False
return result
# NOTE Would this properly work when Alias and Local differ?
def is_member(self, jid_bare, jid_full):
"""Check if given JID is a member"""
alias = jid_full[jid_full.index('/')+1:]
affiliation = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'affiliation')
if affiliation == 'member':
result = True
else:
result = False
return result
result = True if affiliation == 'member' else False
return result