Commit 8f85cb4d authored by Philipp Hörist's avatar Philipp Hörist

steap

parent e230d059
This diff is collapsed.
......@@ -3,8 +3,7 @@ name: OMEMO2
short_name: omemo2
version: 2.5.7
description: OMEMO
authors: Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
Daniel Gultsch <daniel@gultsch.de>
Philipp Hörist <philipp@hoerist.com>
authors: Philipp Hörist <philipp@hoerist.com>
homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/OmemoGajimPlugin
min_gajim_version: 0.16.11.2
min_gajim_version: 1.1.91
max_gajim_version: 1.2.90
This diff is collapsed.
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
# This file is part of OMEMO.
#
# Gajim is free software; you can redistribute it and/or modify
# OMEMO is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# OMEMO 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# along with OMEMO. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
# XEP-0384: OMEMO Encryption
import logging
import nbxmpp
from gajim.common import app
from gajim.common.exceptions import StanzaMalformed
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
from openpgp.modules import util
from omemo2.modules import util
from omemo2.modules.util import unpack_devicelist
log = logging.getLogger('gajim.plugin_system.omemo.pep')
......@@ -37,10 +37,6 @@ class OMEMODevicelistData(AbstractPEPData):
type_ = 'omemo-devicelist'
def __init__(self, devicelist):
self._pep_specific_data = devicelist
self.data = devicelist
class OMEMODevicelist(AbstractPEPModule):
'''
......@@ -58,33 +54,16 @@ class OMEMODevicelist(AbstractPEPModule):
store_publish = True
_log = log
def __init__(self, con):
AbstractPEPModule.__init__(self, con, con.name)
self.handlers = []
def _extract_info(self, item):
list_ = item.getTag('list', namespace=util.NS_OMEMO)
if list_ is None:
raise StanzaMalformed('No list node')
device_list = list_.getTags('device')
devices = []
for device in device_list:
id_ = device.getAttr('id')
if id_ is None:
raise StanzaMalformed('No id for device found')
devices.append(int(id_))
return devices
@staticmethod
def _extract_info(item):
return unpack_devicelist(item)
def _notification_received(self, jid, devicelist):
con = app.connections[self._account]
con.get_module('OMEMO').device_list_received(devicelist.data,
jid.getStripped())
def _build_node(self, devicelist):
@staticmethod
def _build_node(devicelist):
list_node = nbxmpp.Node('list', {'xmlns': util.NS_OMEMO})
if devicelist is None:
return list_node
......
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
# This file is part of OMEMO.
#
# Gajim is free software; you can redistribute it and/or modify
# OMEMO is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# OMEMO 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# along with OMEMO. If not, see <http://www.gnu.org/licenses/>.
# XEP-0384: OMEMO Encryption
......@@ -21,13 +21,13 @@ import logging
from base64 import b64decode, b64encode
import nbxmpp
from nbxmpp.protocol import NS_PUBSUB, Iq
from nbxmpp.protocol import NS_PUBSUB
from nbxmpp.simplexml import Node
from gajim.common import app
from gajim.common.exceptions import StanzaMalformed
from omemo.extendedpublicbundle import ExtendedPublicBundle
from omemo.signal.wireformat import decodePublicKey
from omemo_backend_signal import BACKEND
log = logging.getLogger('gajim.plugin_system.omemo')
......@@ -35,7 +35,7 @@ log = logging.getLogger('gajim.plugin_system.omemo')
NS_OMEMO = 'eu.siacs.conversations.axolotl'
NS_DEVICE_LIST = NS_OMEMO + '.devicelist'
NS_NOTIFY = NS_DEVICE_LIST + '+notify'
NS_BUNDLES = NS_OMEMO + '.bundles:'
NS_BUNDLES = NS_OMEMO + '.bundles'
def build_omemo_stanza(message_node, msg_dict):
......@@ -140,7 +140,7 @@ def unpack_device_bundle(bundle, device_id):
return
spk = {}
spk['key'] = decodePublicKey(decode_data(signed_prekey_node))
spk['key'] = b64decode(signed_prekey_node)
if not spk['key']:
log.warning('OMEMO device bundle has no signedPreKeyPublic data')
return
......@@ -156,7 +156,7 @@ def unpack_device_bundle(bundle, device_id):
log.warning('OMEMO device bundle has no signedPreKeySignature node')
return
spk_signature = decode_data(signed_signature_node)
spk_signature = b64decode(signed_signature_node)
if not spk_signature:
log.warning('OMEMO device bundle has no signedPreKeySignature data')
return
......@@ -166,7 +166,7 @@ def unpack_device_bundle(bundle, device_id):
log.warning('OMEMO device bundle has no identityKey node')
return
identity_key = decodePublicKey(decode_data(identity_key_node))
identity_key = b64decode(identity_key_node)
if not identity_key:
log.warning('OMEMO device bundle has no identityKey data')
return
......@@ -179,11 +179,47 @@ def unpack_device_bundle(bundle, device_id):
otpks = []
for prekey_node in prekeys_node.getChildren():
otpks.append({
"key": decodePublicKey(b64decode(prekey_node.getData())),
"key": b64decode(prekey_node.getData()),
"id": int(prekey_node.getAttr('preKeyId'))
})
return ExtendedPublicBundle(identity_key, spk, spk_signature, otpks)
return ExtendedPublicBundle.parse(
BACKEND, identity_key, spk, spk_signature, otpks)
def get_item_from_pubsub_query(stanza):
pubsub = stanza.getTag('pubsub', namespace=nbxmpp.NS_PUBSUB)
items = pubsub.getTag('items')
if items is None:
raise StanzaMalformed('Malformed query (no items node)')
namespace = items.getAttr('node')
if namespace is None:
raise StanzaMalformed('Malformed query (no node attr)')
if len(items.getChildren()) != 1:
raise StanzaMalformed('Invalid item count received')
item = items.getTag('item')
if item is None:
raise StanzaMalformed('No item node')
return item
def unpack_devicelist(item):
list_ = item.getTag('list', namespace=NS_OMEMO)
if list_ is None:
raise StanzaMalformed('No list node')
device_list = list_.getTags('device')
devices = []
for device in device_list:
id_ = device.getAttr('id')
if id_ is None:
raise StanzaMalformed('No id for device found')
devices.append(int(id_))
return devices
def unpack_encrypted(encrypted_node):
......@@ -207,17 +243,17 @@ def unpack_encrypted(encrypted_node):
log.warning("OMEMO message without iv")
return
iv = decode_data(iv_node)
iv = b64decode(iv_node)
if not iv:
log.warning("OMEMO message without iv data")
payload_node = encrypted_node.getTag('payload', namespace=NS_OMEMO)
payload = None
if payload_node:
payload = decode_data(payload_node)
payload = b64decode(payload_node)
key_nodes = header_node.getTags('key')
if len(key_nodes) < 1:
if not key_nodes:
log.warning("OMEMO message without keys")
return
......@@ -236,26 +272,7 @@ def unpack_encrypted(encrypted_node):
if kn.getAttr('prekey') == 'true':
prekey = True
keys[int(rid)] = (decode_data(kn), prekey)
keys[int(rid)] = (b64decode(kn), prekey)
result = {'sid': sid, 'iv': iv, 'keys': keys, 'payload': payload}
return result
def decode_data(node):
""" Fetch the data from specified node and b64decode it. """
data = node.getData()
if not data:
log.warning("No node data")
return
try:
return b64decode(data)
except:
log.warning('b64decode broken')
return
def successful(stanza):
""" Check if stanza type is result. """
return stanza.getAttr('type') == 'result'
import logging
import omemo
from omemo import OTPKPolicy
from omemo import SessionManager as SessionMgr
from omemo_backend_signal import BACKEND
from .storage import SQLiteDatabase
log = logging.getLogger('gajim.plugin_system.omemo.session_manager')
class KeepingOTPKPolicy(omemo.OTPKPolicy):
class KeepingOTPKPolicy(OTPKPolicy):
@staticmethod
def decideOTPK(preKeyMessages):
# Always keep the OTPK.
......@@ -21,16 +23,17 @@ class SessionManager:
# Database Inferface
self._store = SQLiteDatabase(db_path, own_jid)
# OmemoSessionManager
self._sm = omemo.SessionManager.create(self._store,
KeepingOTPKPolicy(),
own_jid,
self._store.own_device_id)
self._sm = SessionMgr.create(self._store,
KeepingOTPKPolicy(),
BACKEND,
own_jid,
self._store.own_device_id)
def build_session(self, bundle):
self._store.createSession()
def get_bundle(self):
return self._sm.state.getPublicBundle()
return self._sm.public_bundle
def set_devicelist(self, device_list, jid=None):
self._sm.newDeviceList(device_list, jid)
......
......@@ -18,15 +18,11 @@
#
import sqlite3
import pickle
import json
import logging
from collections import namedtuple
from omemo.storage import Storage
from omemo.x3dhdoubleratchet import X3DHDoubleRatchet
import json
from omemo.signal.doubleratchet.doubleratchet import DoubleRatchet
from omemo.util import generateDeviceID
from .db_helpers import user_version
......@@ -76,8 +72,7 @@ class SQLiteDatabase(Storage):
UNIQUE(jid, device_id));
CREATE TABLE IF NOT EXISTS state (
_id INTEGER PRIMARY KEY,
device_id INTEGER,
device_id INTEGER PRIMARY KEY,
state omemo_state BLOB
);
'''
......@@ -111,11 +106,14 @@ class SQLiteDatabase(Storage):
return named_row
def _load_own_device_id(self):
q = 'SELECT device_id FROM state'
result = self._con.execute(q).fetchone()
query = 'SELECT device_id FROM state'
result = self._con.execute(query).fetchone()
if result is None:
log.info('Generate new device id')
device_id = generateDeviceID()
query = 'INSERT INTO state(device_id) VALUES(?)'
self._con.execute(query, (device_id,))
self._con.commit()
else:
device_id = result.device_id
log.info('Load own device id: %s', device_id)
......@@ -129,31 +127,30 @@ class SQLiteDatabase(Storage):
# useless
return
def loadState(self, callback):
def loadState(self, _callback):
log.info('Load State')
q = 'SELECT state FROM state'
result = self._con.execute(q).fetchone()
query = 'SELECT state FROM state'
result = self._con.execute(query).fetchone()
if result is not None:
self._own_device_id = result.device_id
return result.state
def storeState(self, callback, state):
def storeState(self, _callback, state):
log.info('Store State')
q = 'INSERT OR REPLACE INTO state(state) VALUES(?)'
self._con.execute(q, (state,))
query = 'INSERT OR REPLACE INTO state(device_id, state) VALUES(?, ?)'
self._con.execute(query, (self.own_device_id, state))
self._con.commit()
def loadSession(self, callback, bare_jid, device_id):
log.info('Load Session')
q = 'SELECT session FROM sessions WHERE jid = ? AND device_id = ?'
result = self._con.execute(q, (bare_jid, device_id)).fetchone()
query = 'SELECT session FROM sessions WHERE jid = ? AND device_id = ?'
result = self._con.execute(query, (bare_jid, device_id)).fetchone()
if result is not None:
return result.session
def storeSession(self, callback, bare_jid, device_id, session):
log.info('Store Session: %s, %s', bare_jid, device_id)
q = 'UPDATE sessions SET session = ? WHERE jid= ? AND device_id = ?'
self._con.execute(q, (session, bare_jid, device_id))
query = 'UPDATE sessions SET session = ? WHERE jid= ? AND device_id = ?'
self._con.execute(query, (session, bare_jid, device_id))
self._con.commit()
def createSession(self, jid, device_id, session):
......@@ -179,17 +176,20 @@ class SQLiteDatabase(Storage):
return devices
return []
def storeActiveDevices(self, callback, bare_jid, devices):
def storeActiveDevices(self, _callback, bare_jid, devices):
if not devices:
return
# python-omemo returns own device as active,
# dont store it in this table
if self._own_device_id in devices:
devices.remove(self._own_device_id)
if not devices:
return
log.info('Store Active Devices: %s, %s', bare_jid, devices)
self.storeDevices(bare_jid, devices, 1)
def storeInactiveDevices(self, callback, bare_jid, devices):
def storeInactiveDevices(self, _callback, bare_jid, devices):
if not devices:
return
log.info('Store Inactive Devices: %s, %s', bare_jid, devices)
......
# -*- coding: utf-8 -*-
'''
Copyright 2015 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
Copyright 2015 Daniel Gultsch <daniel@cgultsch.de>
Copyright 2016 Philipp Hörist <philipp@hoerist.com>
This file is part of Gajim-OMEMO plugin.
The Gajim-OMEMO plugin is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
Gajim-OMEMO 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 GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
the Gajim-OMEMO plugin. If not, see <http://www.gnu.org/licenses/>.
'''
# Copyright 2016 Philipp Hörist <philipp@hoerist.com>
#
# This file is part of Gajim-OMEMO plugin.
#
# The Gajim-OMEMO plugin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# Gajim-OMEMO 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 GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the Gajim-OMEMO plugin. If not, see <http://www.gnu.org/licenses/>.
import logging
import binascii
......@@ -34,6 +28,8 @@ from gajim.plugins import GajimPlugin
from gajim.groupchat_control import GroupchatControl
from omemo2.modules.util import NS_NOTIFY
from omemo2.modules import omemo_devicelist
from omemo2.modules import omemo
CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography'
AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version'
......@@ -58,9 +54,6 @@ if not ERROR_MSG:
log.error(error)
ERROR_MSG = 'Error: %s' % error
# pylint: disable=no-init
# pylint: disable=attribute-defined-outside-init
@unique
class UserMessages(IntEnum):
......@@ -70,7 +63,6 @@ class UserMessages(IntEnum):
class OmemoPlugin(GajimPlugin):
def init(self):
""" Init """
if ERROR_MSG:
self.activatable = False
self.available_text = ERROR_MSG
......@@ -78,6 +70,8 @@ class OmemoPlugin(GajimPlugin):
return
self.encryption_name = 'OMEMO'
self.allow_groupchat = True
self.modules = [omemo_devicelist,
omemo]
self.events_handlers = {
'signed-in': (ged.PRECORE, self._signed_in),
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment