Add chat command for omemo;

Fix NameError: name 'XmppChat' is not defined of function XmppOmemo.decrypt.
This commit is contained in:
Schimon Jehudah, Adv. 2024-07-07 11:16:00 +03:00
parent f9a1c683cd
commit 51943b5b0c
7 changed files with 119 additions and 38 deletions

View file

@ -36,6 +36,7 @@ NOTE
"""
import aiofiles
from aiohttp import ClientError, ClientSession, ClientTimeout
from asyncio import TimeoutError
# from asyncio.exceptions import IncompleteReadError
@ -135,6 +136,9 @@ class Http:
) as response:
status = response.status
if status in (200, 201):
f = await aiofiles.open(pathname, mode='wb')
await f.write(await response.read())
await f.close()
try:
result = {'charset': response.charset,
'content_length': response.content_length,

View file

@ -327,6 +327,7 @@ class Html:
'//img[not('
'contains(@src, "avatar") or '
'contains(@src, "cc-by-sa") or '
'contains(@src, "data:image/") or '
'contains(@src, "emoji") or '
'contains(@src, "icon") or '
'contains(@src, "logo") or '

View file

@ -1,2 +1,2 @@
__version__ = '0.1.87'
__version_info__ = (0, 1, 87)
__version__ = '0.1.88'
__version_info__ = (0, 1, 88)

View file

@ -46,6 +46,7 @@ from slixmpp import JID
from slixmpp.stanza import Message
import sys
import time
from typing import Optional
logger = Logger(__name__)
@ -150,8 +151,11 @@ class XmppChat:
# await compose.message(self, jid_bare, message)
if self['xep_0384'].is_encrypted(message):
command, omemo_decrypted = await XmppOmemo.decrypt(
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
self, message, allow_untrusted)
if retry:
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
self, message, allow_untrusted=True)
else:
omemo_decrypted = None
@ -353,6 +357,11 @@ class XmppChat:
# XmppMessage.send_oob_reply_message(message, url, response)
if url:
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if encrypted:
url_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, JID(jid_bare), url)
XmppMessage.send_omemo_oob(self, JID(jid_bare), url_encrypted, chat_type)
else:
XmppMessage.send_oob(self, jid_bare, url, chat_type)
else:
response = 'OPML file export has been failed.'
@ -473,6 +482,13 @@ class XmppChat:
self, jid_bare, db_file)
case _ if command_lowercase.startswith('next'):
num = command[5:]
if num:
try:
int(num)
except:
# NOTE Show this text as a status message
# response = 'Argument for command "next" must be an integer.'
num = None
await XmppChatAction.send_unread_items(self, jid_bare, num)
XmppStatusTask.restart_task(self, jid_bare)
case _ if command_lowercase.startswith('node delete'):
@ -494,6 +510,12 @@ class XmppChat:
case 'old':
response = await XmppCommands.set_old_on(
self, jid_bare, db_file)
case 'omemo off':
response = await XmppCommands.set_omemo_off(
self, jid_bare, db_file)
case 'omemo on':
response = await XmppCommands.set_omemo_on(
self, jid_bare, db_file)
case 'options':
response = 'Options:\n```'
response += XmppCommands.print_options(self, jid_bare)
@ -572,9 +594,9 @@ class XmppChat:
XmppPresence.send(self, jid_bare, status_message,
status_type=status_type)
await asyncio.sleep(5)
tasks = (FeedTask, XmppChatTask, XmppStatusTask)
callbacks = (FeedTask, XmppChatTask, XmppStatusTask)
response = await XmppCommands.scheduler_start(
self, db_file, jid_bare, tasks)
self, db_file, jid_bare, callbacks)
case 'stats':
response = XmppCommands.print_statistics(db_file)
case 'stop':
@ -639,7 +661,7 @@ class XmppChat:
class XmppChatAction:
async def send_unread_items(self, jid_bare, num=None):
async def send_unread_items(self, jid_bare, num: Optional[int] = None):
"""
Send news items as messages.
@ -693,6 +715,17 @@ class XmppChatAction:
media_url = enclosure
else:
media_url = await Html.extract_image_from_html(url)
try:
http_headers = await Http.fetch_headers(media_url)
if ('Content-Length' in http_headers):
if int(http_headers['Content-Length']) < 100000:
media_url = None
else:
media_url = None
except Exception as e:
print(media_url)
logger.error(e)
media_url = None
if media_url and news_digest:
if encrypt_omemo:
@ -707,32 +740,53 @@ class XmppChatAction:
# Send media
if encrypt_omemo:
cache_dir = config.get_default_cache_directory()
# if not media_url.startswith('data:'):
filename = media_url.split('/').pop().split('?')[0]
if not filename: breakpoint()
pathname = os.path.join(cache_dir, filename)
# http_response = await Http.response(media_url)
# http_headers = await Http.fetch_headers(media_url)
# breakpoint()
# status = Http.fetch_media(media_url, pathname)
# if status:
http_headers = await Http.fetch_headers(media_url)
if ('Content-Length' in http_headers and
int(http_headers['Content-Length']) < 3000000):
status = await Http.fetch_media(media_url, pathname)
if status:
filesize = os.path.getsize(pathname)
media_url_new = await XmppUpload.start(
self, jid_bare, Path(pathname), filesize, encrypted=encrypted)
else:
media_url_new = media_url
else:
media_url_new = media_url
# else:
# import io, base64
# from PIL import Image
# file_content = media_url.split(',').pop()
# file_extension = media_url.split(';')[0].split(':').pop().split('/').pop()
# img = Image.open(io.BytesIO(base64.decodebytes(bytes(file_content, "utf-8"))))
# filename = 'image.' + file_extension
# pathname = os.path.join(cache_dir, filename)
# img.save(pathname)
# filesize = os.path.getsize(pathname)
# media_url_new = await XmppUpload.start(
# self, jid_bare, Path(pathname), filesize, encrypted=encrypted)
# else:
# media_url_new = media_url
media_url_new = media_url
media_url_new_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, media_url_new)
# NOTE Temporary line!
XmppMessage.send_omemo_oob(self, jid_bare, media_url_new_encrypted, chat_type)
# if media_url_new_encrypted and omemo_encrypted:
# XmppMessage.send_omemo_oob(self, jid, media_url_new_encrypted, chat_type)
# elif media_url:
# XmppMessage.send_oob(self, jid_bare, media_url_new_encrypted, chat_type)
if media_url_new_encrypted and omemo_encrypted:
# NOTE Tested against Gajim.
# FIXME This only works with aesgcm URLs, and it does
# not work with http URLs.
# url = saxutils.escape(url)
# AttributeError: 'Encrypted' object has no attribute 'replace'
XmppMessage.send_omemo_oob(self, jid, media_url_new_encrypted, chat_type)
else:
# NOTE Tested against Gajim.
# FIXME Jandle data: URIs.
if not media_url.startswith('data:'):
http_headers = await Http.fetch_headers(media_url)
if ('Content-Length' in http_headers and
int(http_headers['Content-Length']) > 100000):
print(http_headers['Content-Length'])
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
else:
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
media_url = None

View file

@ -43,7 +43,6 @@ import slixmpp
# import xml.etree.ElementTree as ET
# from lxml import etree
from omemo.exceptions import MissingBundleException
import slixfeed.config as config
from slixfeed.config import Config, Data
import slixfeed.fetch as fetch
@ -55,11 +54,12 @@ 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
from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.muc import XmppMuc
from slixfeed.xmpp.groupchat import XmppGroupchat
from slixfeed.xmpp.presence import XmppPresence
import slixfeed.xmpp.profile as profile
from slixfeed.xmpp.publish import XmppPubsub, XmppPubsubAction, XmppPubsubTask
@ -68,9 +68,9 @@ from slixfeed.xmpp.roster import XmppRoster
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, MissingOwnKey, EncryptionPrepareException
from slixmpp_omemo import UndecidedException, UntrustedException, NoAvailableSession
from slixmpp_omemo import PluginCouldNotLoad
import sys
import time
@ -2906,6 +2906,11 @@ class XmppClient(slixmpp.ClientXMPP):
if url:
form['instructions'] = 'Export has been completed successfully!'
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if encrypted:
url_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, JID(jid_bare), url)
XmppMessage.send_omemo_oob(self, JID(jid_bare), url_encrypted, chat_type)
else:
XmppMessage.send_oob(self, jid_bare, url, chat_type)
url_field = form.add_field(var=ext.upper(),
ftype='text-single',

View file

@ -648,6 +648,18 @@ class XmppCommands:
return message
async def set_omemo_off(self, jid_bare, db_file):
await Config.set_setting_value(self.settings, jid_bare, db_file, 'omemo', 0)
message = 'OMEMO is disabled.'
return message
async def set_omemo_on(self, jid_bare, db_file):
await Config.set_setting_value(self.settings, jid_bare, db_file, 'omemo', 1)
message = 'OMEMO is enabled.'
return message
def node_delete(self, info):
info = info.split(' ')
if len(info) > 2:
@ -958,10 +970,10 @@ class XmppCommands:
# Tasks are classes which are passed to this function
# On an occasion in which they would have returned, variable "tasks" might be called "callback"
async def scheduler_start(self, db_file, jid_bare, tasks):
async def scheduler_start(self, db_file, jid_bare, callbacks):
await Config.set_setting_value(self.settings, jid_bare, db_file, 'enabled', 1)
for task in tasks:
task.restart_task(self, jid_bare)
for callback in callbacks:
callback.restart_task(self, jid_bare)
message = 'Updates are enabled.'
return message

View file

@ -23,13 +23,13 @@ TODO
"""
from omemo.exceptions import MissingBundleException
from slixfeed.log import Logger
from slixmpp import JID
from slixmpp.exceptions import IqTimeout, IqError
from slixmpp.stanza import Message
from slixmpp_omemo import PluginCouldNotLoad, MissingOwnKey, EncryptionPrepareException
from slixmpp_omemo import MissingOwnKey, EncryptionPrepareException
from slixmpp_omemo import UndecidedException, UntrustedException, NoAvailableSession
from omemo.exceptions import MissingBundleException
logger = Logger(__name__)
@ -66,6 +66,7 @@ class XmppOmemo:
response = ('Error: Your message has not been encrypted for '
'Slixfeed (MissingOwnKey).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (NoAvailableSession,) as exn:
# We received a message from that contained a session that we
@ -77,6 +78,7 @@ class XmppOmemo:
response = ('Error: Your message has not been encrypted for '
'Slixfeed (NoAvailableSession).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (UndecidedException, UntrustedException) as exn:
# We received a message from an untrusted device. We can
@ -90,9 +92,10 @@ class XmppOmemo:
response = (f'Error: Device "{exn.device}" is not present in the '
'trusted devices of Slixfeed.')
omemo_decrypted = False
retry = True
logger.error(exn)
# We resend, setting the `allow_untrusted` parameter to True.
await XmppChat.process_message(self, message, allow_untrusted=True)
# await XmppChat.process_message(self, message, allow_untrusted=True)
except (EncryptionPrepareException,) as exn:
# Slixmpp tried its best, but there were errors it couldn't
# resolve. At this point you should have seen other exceptions
@ -100,15 +103,17 @@ class XmppOmemo:
response = ('Error: Your message has not been encrypted for '
'Slixfeed (EncryptionPrepareException).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (Exception,) as exn:
response = ('Error: Your message has not been encrypted for '
'Slixfeed (Unknown).')
omemo_decrypted = False
retry = False
logger.error(exn)
raise
return response, omemo_decrypted
return response, omemo_decrypted, retry
async def encrypt(self, jid: JID, message_body):