forked from sch/Slixfeed
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 aiohttp import ClientError, ClientSession, ClientTimeout
|
||||||
from asyncio import TimeoutError
|
from asyncio import TimeoutError
|
||||||
# from asyncio.exceptions import IncompleteReadError
|
# from asyncio.exceptions import IncompleteReadError
|
||||||
|
@ -135,6 +136,9 @@ class Http:
|
||||||
) as response:
|
) as response:
|
||||||
status = response.status
|
status = response.status
|
||||||
if status in (200, 201):
|
if status in (200, 201):
|
||||||
|
f = await aiofiles.open(pathname, mode='wb')
|
||||||
|
await f.write(await response.read())
|
||||||
|
await f.close()
|
||||||
try:
|
try:
|
||||||
result = {'charset': response.charset,
|
result = {'charset': response.charset,
|
||||||
'content_length': response.content_length,
|
'content_length': response.content_length,
|
||||||
|
|
|
@ -327,6 +327,7 @@ class Html:
|
||||||
'//img[not('
|
'//img[not('
|
||||||
'contains(@src, "avatar") or '
|
'contains(@src, "avatar") or '
|
||||||
'contains(@src, "cc-by-sa") or '
|
'contains(@src, "cc-by-sa") or '
|
||||||
|
'contains(@src, "data:image/") or '
|
||||||
'contains(@src, "emoji") or '
|
'contains(@src, "emoji") or '
|
||||||
'contains(@src, "icon") or '
|
'contains(@src, "icon") or '
|
||||||
'contains(@src, "logo") or '
|
'contains(@src, "logo") or '
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
__version__ = '0.1.87'
|
__version__ = '0.1.88'
|
||||||
__version_info__ = (0, 1, 87)
|
__version_info__ = (0, 1, 88)
|
||||||
|
|
|
@ -46,6 +46,7 @@ from slixmpp import JID
|
||||||
from slixmpp.stanza import Message
|
from slixmpp.stanza import Message
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
logger = Logger(__name__)
|
logger = Logger(__name__)
|
||||||
|
@ -150,8 +151,11 @@ class XmppChat:
|
||||||
# await compose.message(self, jid_bare, message)
|
# await compose.message(self, jid_bare, message)
|
||||||
|
|
||||||
if self['xep_0384'].is_encrypted(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)
|
self, message, allow_untrusted)
|
||||||
|
if retry:
|
||||||
|
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
|
||||||
|
self, message, allow_untrusted=True)
|
||||||
else:
|
else:
|
||||||
omemo_decrypted = None
|
omemo_decrypted = None
|
||||||
|
|
||||||
|
@ -353,6 +357,11 @@ class XmppChat:
|
||||||
# XmppMessage.send_oob_reply_message(message, url, response)
|
# XmppMessage.send_oob_reply_message(message, url, response)
|
||||||
if url:
|
if url:
|
||||||
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
|
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)
|
XmppMessage.send_oob(self, jid_bare, url, chat_type)
|
||||||
else:
|
else:
|
||||||
response = 'OPML file export has been failed.'
|
response = 'OPML file export has been failed.'
|
||||||
|
@ -473,6 +482,13 @@ class XmppChat:
|
||||||
self, jid_bare, db_file)
|
self, jid_bare, db_file)
|
||||||
case _ if command_lowercase.startswith('next'):
|
case _ if command_lowercase.startswith('next'):
|
||||||
num = command[5:]
|
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)
|
await XmppChatAction.send_unread_items(self, jid_bare, num)
|
||||||
XmppStatusTask.restart_task(self, jid_bare)
|
XmppStatusTask.restart_task(self, jid_bare)
|
||||||
case _ if command_lowercase.startswith('node delete'):
|
case _ if command_lowercase.startswith('node delete'):
|
||||||
|
@ -494,6 +510,12 @@ class XmppChat:
|
||||||
case 'old':
|
case 'old':
|
||||||
response = await XmppCommands.set_old_on(
|
response = await XmppCommands.set_old_on(
|
||||||
self, jid_bare, db_file)
|
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':
|
case 'options':
|
||||||
response = 'Options:\n```'
|
response = 'Options:\n```'
|
||||||
response += XmppCommands.print_options(self, jid_bare)
|
response += XmppCommands.print_options(self, jid_bare)
|
||||||
|
@ -572,9 +594,9 @@ class XmppChat:
|
||||||
XmppPresence.send(self, jid_bare, status_message,
|
XmppPresence.send(self, jid_bare, status_message,
|
||||||
status_type=status_type)
|
status_type=status_type)
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
tasks = (FeedTask, XmppChatTask, XmppStatusTask)
|
callbacks = (FeedTask, XmppChatTask, XmppStatusTask)
|
||||||
response = await XmppCommands.scheduler_start(
|
response = await XmppCommands.scheduler_start(
|
||||||
self, db_file, jid_bare, tasks)
|
self, db_file, jid_bare, callbacks)
|
||||||
case 'stats':
|
case 'stats':
|
||||||
response = XmppCommands.print_statistics(db_file)
|
response = XmppCommands.print_statistics(db_file)
|
||||||
case 'stop':
|
case 'stop':
|
||||||
|
@ -639,7 +661,7 @@ class XmppChat:
|
||||||
class XmppChatAction:
|
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.
|
Send news items as messages.
|
||||||
|
|
||||||
|
@ -693,6 +715,17 @@ class XmppChatAction:
|
||||||
media_url = enclosure
|
media_url = enclosure
|
||||||
else:
|
else:
|
||||||
media_url = await Html.extract_image_from_html(url)
|
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 media_url and news_digest:
|
||||||
if encrypt_omemo:
|
if encrypt_omemo:
|
||||||
|
@ -707,32 +740,53 @@ class XmppChatAction:
|
||||||
# Send media
|
# Send media
|
||||||
if encrypt_omemo:
|
if encrypt_omemo:
|
||||||
cache_dir = config.get_default_cache_directory()
|
cache_dir = config.get_default_cache_directory()
|
||||||
|
# if not media_url.startswith('data:'):
|
||||||
filename = media_url.split('/').pop().split('?')[0]
|
filename = media_url.split('/').pop().split('?')[0]
|
||||||
|
if not filename: breakpoint()
|
||||||
pathname = os.path.join(cache_dir, filename)
|
pathname = os.path.join(cache_dir, filename)
|
||||||
# http_response = await Http.response(media_url)
|
# http_response = await Http.response(media_url)
|
||||||
|
http_headers = await Http.fetch_headers(media_url)
|
||||||
# http_headers = await Http.fetch_headers(media_url)
|
if ('Content-Length' in http_headers and
|
||||||
# breakpoint()
|
int(http_headers['Content-Length']) < 3000000):
|
||||||
# status = Http.fetch_media(media_url, pathname)
|
status = await Http.fetch_media(media_url, pathname)
|
||||||
# if status:
|
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)
|
# filesize = os.path.getsize(pathname)
|
||||||
# media_url_new = await XmppUpload.start(
|
# media_url_new = await XmppUpload.start(
|
||||||
# self, jid_bare, Path(pathname), filesize, encrypted=encrypted)
|
# 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(
|
media_url_new_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
|
||||||
self, jid, media_url_new)
|
self, jid, media_url_new)
|
||||||
|
if media_url_new_encrypted and omemo_encrypted:
|
||||||
# NOTE Temporary line!
|
# NOTE Tested against Gajim.
|
||||||
XmppMessage.send_omemo_oob(self, jid_bare, media_url_new_encrypted, chat_type)
|
# FIXME This only works with aesgcm URLs, and it does
|
||||||
|
# not work with http URLs.
|
||||||
|
# url = saxutils.escape(url)
|
||||||
# if media_url_new_encrypted and omemo_encrypted:
|
# AttributeError: 'Encrypted' object has no attribute 'replace'
|
||||||
# XmppMessage.send_omemo_oob(self, jid, media_url_new_encrypted, chat_type)
|
XmppMessage.send_omemo_oob(self, jid, media_url_new_encrypted, chat_type)
|
||||||
# elif media_url:
|
else:
|
||||||
# XmppMessage.send_oob(self, jid_bare, media_url_new_encrypted, chat_type)
|
# 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:
|
else:
|
||||||
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
|
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
|
||||||
media_url = None
|
media_url = None
|
||||||
|
|
|
@ -43,7 +43,6 @@ import slixmpp
|
||||||
# import xml.etree.ElementTree as ET
|
# import xml.etree.ElementTree as ET
|
||||||
# from lxml import etree
|
# from lxml import etree
|
||||||
|
|
||||||
from omemo.exceptions import MissingBundleException
|
|
||||||
import slixfeed.config as config
|
import slixfeed.config as config
|
||||||
from slixfeed.config import Config, Data
|
from slixfeed.config import Config, Data
|
||||||
import slixfeed.fetch as fetch
|
import slixfeed.fetch as fetch
|
||||||
|
@ -55,11 +54,12 @@ from slixfeed.version import __version__
|
||||||
from slixfeed.xmpp.bookmark import XmppBookmark
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
from slixfeed.xmpp.chat import XmppChat, XmppChatTask
|
from slixfeed.xmpp.chat import XmppChat, XmppChatTask
|
||||||
from slixfeed.xmpp.connect import XmppConnect, XmppConnectTask
|
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.ipc import XmppIpcServer
|
||||||
from slixfeed.xmpp.iq import XmppIQ
|
from slixfeed.xmpp.iq import XmppIQ
|
||||||
from slixfeed.xmpp.message import XmppMessage
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
from slixfeed.xmpp.muc import XmppMuc
|
from slixfeed.xmpp.muc import XmppMuc
|
||||||
from slixfeed.xmpp.groupchat import XmppGroupchat
|
|
||||||
from slixfeed.xmpp.presence import XmppPresence
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
import slixfeed.xmpp.profile as profile
|
import slixfeed.xmpp.profile as profile
|
||||||
from slixfeed.xmpp.publish import XmppPubsub, XmppPubsubAction, XmppPubsubTask
|
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.status import XmppStatusTask
|
||||||
from slixfeed.xmpp.upload import XmppUpload
|
from slixfeed.xmpp.upload import XmppUpload
|
||||||
from slixfeed.xmpp.utilities import XmppUtilities
|
from slixfeed.xmpp.utilities import XmppUtilities
|
||||||
|
from slixmpp import JID
|
||||||
import slixmpp_omemo
|
import slixmpp_omemo
|
||||||
from slixmpp_omemo import PluginCouldNotLoad, MissingOwnKey, EncryptionPrepareException
|
from slixmpp_omemo import PluginCouldNotLoad
|
||||||
from slixmpp_omemo import UndecidedException, UntrustedException, NoAvailableSession
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -2906,6 +2906,11 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
if url:
|
if url:
|
||||||
form['instructions'] = 'Export has been completed successfully!'
|
form['instructions'] = 'Export has been completed successfully!'
|
||||||
chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
|
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)
|
XmppMessage.send_oob(self, jid_bare, url, chat_type)
|
||||||
url_field = form.add_field(var=ext.upper(),
|
url_field = form.add_field(var=ext.upper(),
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
|
|
|
@ -648,6 +648,18 @@ class XmppCommands:
|
||||||
return message
|
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):
|
def node_delete(self, info):
|
||||||
info = info.split(' ')
|
info = info.split(' ')
|
||||||
if len(info) > 2:
|
if len(info) > 2:
|
||||||
|
@ -958,10 +970,10 @@ class XmppCommands:
|
||||||
|
|
||||||
# Tasks are classes which are passed to this function
|
# Tasks are classes which are passed to this function
|
||||||
# On an occasion in which they would have returned, variable "tasks" might be called "callback"
|
# 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)
|
await Config.set_setting_value(self.settings, jid_bare, db_file, 'enabled', 1)
|
||||||
for task in tasks:
|
for callback in callbacks:
|
||||||
task.restart_task(self, jid_bare)
|
callback.restart_task(self, jid_bare)
|
||||||
message = 'Updates are enabled.'
|
message = 'Updates are enabled.'
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,13 @@ TODO
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from omemo.exceptions import MissingBundleException
|
||||||
from slixfeed.log import Logger
|
from slixfeed.log import Logger
|
||||||
from slixmpp import JID
|
from slixmpp import JID
|
||||||
from slixmpp.exceptions import IqTimeout, IqError
|
from slixmpp.exceptions import IqTimeout, IqError
|
||||||
from slixmpp.stanza import Message
|
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 slixmpp_omemo import UndecidedException, UntrustedException, NoAvailableSession
|
||||||
from omemo.exceptions import MissingBundleException
|
|
||||||
|
|
||||||
|
|
||||||
logger = Logger(__name__)
|
logger = Logger(__name__)
|
||||||
|
@ -66,6 +66,7 @@ class XmppOmemo:
|
||||||
response = ('Error: Your message has not been encrypted for '
|
response = ('Error: Your message has not been encrypted for '
|
||||||
'Slixfeed (MissingOwnKey).')
|
'Slixfeed (MissingOwnKey).')
|
||||||
omemo_decrypted = False
|
omemo_decrypted = False
|
||||||
|
retry = False
|
||||||
logger.error(exn)
|
logger.error(exn)
|
||||||
except (NoAvailableSession,) as exn:
|
except (NoAvailableSession,) as exn:
|
||||||
# We received a message from that contained a session that we
|
# 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 '
|
response = ('Error: Your message has not been encrypted for '
|
||||||
'Slixfeed (NoAvailableSession).')
|
'Slixfeed (NoAvailableSession).')
|
||||||
omemo_decrypted = False
|
omemo_decrypted = False
|
||||||
|
retry = False
|
||||||
logger.error(exn)
|
logger.error(exn)
|
||||||
except (UndecidedException, UntrustedException) as exn:
|
except (UndecidedException, UntrustedException) as exn:
|
||||||
# We received a message from an untrusted device. We can
|
# 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 '
|
response = (f'Error: Device "{exn.device}" is not present in the '
|
||||||
'trusted devices of Slixfeed.')
|
'trusted devices of Slixfeed.')
|
||||||
omemo_decrypted = False
|
omemo_decrypted = False
|
||||||
|
retry = True
|
||||||
logger.error(exn)
|
logger.error(exn)
|
||||||
# We resend, setting the `allow_untrusted` parameter to True.
|
# 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:
|
except (EncryptionPrepareException,) as exn:
|
||||||
# Slixmpp tried its best, but there were errors it couldn't
|
# Slixmpp tried its best, but there were errors it couldn't
|
||||||
# resolve. At this point you should have seen other exceptions
|
# 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 '
|
response = ('Error: Your message has not been encrypted for '
|
||||||
'Slixfeed (EncryptionPrepareException).')
|
'Slixfeed (EncryptionPrepareException).')
|
||||||
omemo_decrypted = False
|
omemo_decrypted = False
|
||||||
|
retry = False
|
||||||
logger.error(exn)
|
logger.error(exn)
|
||||||
except (Exception,) as exn:
|
except (Exception,) as exn:
|
||||||
response = ('Error: Your message has not been encrypted for '
|
response = ('Error: Your message has not been encrypted for '
|
||||||
'Slixfeed (Unknown).')
|
'Slixfeed (Unknown).')
|
||||||
omemo_decrypted = False
|
omemo_decrypted = False
|
||||||
|
retry = False
|
||||||
logger.error(exn)
|
logger.error(exn)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return response, omemo_decrypted
|
return response, omemo_decrypted, retry
|
||||||
|
|
||||||
|
|
||||||
async def encrypt(self, jid: JID, message_body):
|
async def encrypt(self, jid: JID, message_body):
|
||||||
|
|
Loading…
Reference in a new issue