Add chat command for omemo;
Fix NameError: name 'XmppChat' is not defined of function XmppOmemo.decrypt.
This commit is contained in:
parent
f9a1c683cd
commit
51943b5b0c
7 changed files with 119 additions and 38 deletions
|
@ -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,
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
__version__ = '0.1.87'
|
||||
__version_info__ = (0, 1, 87)
|
||||
__version__ = '0.1.88'
|
||||
__version_info__ = (0, 1, 88)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in a new issue