package org.awesomeapp.messenger.crypto.omemo;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smackx.omemo.OmemoInitializer;
import org.jivesoftware.smackx.omemo.OmemoManager;
import org.jivesoftware.smackx.omemo.OmemoService;
import org.jivesoftware.smackx.omemo.elements.OmemoBundleElement;
import org.jivesoftware.smackx.omemo.elements.OmemoDeviceListElement;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.signal.SignalFileBasedOmemoStore;
import org.jivesoftware.smackx.omemo.signal.SignalOmemoService;
import org.jivesoftware.smackx.omemo.signal.SignalOmemoSession;
import org.jivesoftware.smackx.omemo.util.KeyUtil;
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.FullJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.whispersystems.libsignal.IdentityKey;
import java.io.File;
import java.util.ArrayList;
/**
* Created by n8fr8 on 3/30/17.
*/
public class Omemo {
private final static String TAG = "OMEMO";
private OmemoManager mOmemoManager;
private SignalOmemoService mOmemoService;
private SignalFileBasedOmemoStore mOmemoStore;
{
new OmemoInitializer().initialize();
}
public OmemoService getService ()
{
return mOmemoService;
}
public OmemoManager getManager ()
{
return mOmemoManager;
}
public Omemo (XMPPTCPConnection connection, Context context) throws Exception
{
mOmemoManager = OmemoManager.getInstanceFor(connection);
if (mOmemoStore == null)
{
File fileOmemoStore = new File(context.getFilesDir(),"omemo.store");
mOmemoStore = new SignalFileBasedOmemoStore(mOmemoManager, fileOmemoStore);
}
mOmemoService = new SignalOmemoService(mOmemoManager, mOmemoStore);
mOmemoManager.setAddOmemoHintBody(false);
mOmemoManager.initialize();
// mOmemoManager.purgeDevices();
}
public void close ()
{
//do we need to do anything to reinit on reconnect?
}
public ArrayList<String> getFingerprints (BareJid jid, boolean autoload) throws CorruptedOmemoKeyException, SmackException, XMPPException.XMPPErrorException, InterruptedException
{
if (autoload)
loadDeviceList(jid);
CachedDeviceList list = mOmemoStore.loadCachedDeviceList(jid);
if(list == null) {
list = new CachedDeviceList();
}
ArrayList<String> fps = new ArrayList<>();
for(int id : list.getActiveDevices()) {
OmemoDevice device = new OmemoDevice(jid, id);
if (mOmemoStore.loadOmemoIdentityKey(device)!=null) {
String fingerprint = mOmemoStore.getFingerprint(device);
if (!TextUtils.isEmpty(fingerprint))
fps.add(KeyUtil.prettyFingerprint(fingerprint));
}
}
return fps;
}
/**
public ArrayList<String> getJidWithFingerprint (BareJid jid) throws CorruptedOmemoKeyException, SmackException, XMPPException.XMPPErrorException, InterruptedException
{
CachedDeviceList list = mOmemoStore.loadCachedDeviceList(jid);
if(list == null) {
list = new CachedDeviceList();
}
ArrayList<String> fps = new ArrayList<>();
for(int id : list.getActiveDevices()) {
IdentityKey idk = mOmemoStore.loadOmemoIdentityKey(new OmemoDevice(jid, id));
if(idk != null) {
fps.add(KeyUtil.prettyFingerprint(mOmemoStore.keyUtil().getFingerprint(idk)));
} else {
OmemoBundleElement b = mOmemoService.getPubSubHelper().fetchBundle(new OmemoDevice(jid, id));
idk = mOmemoStore.keyUtil().identityKeyFromBytes(b.getIdentityKey());
if(idk != null) {
fps.add(KeyUtil.prettyFingerprint(mOmemoStore.keyUtil().getFingerprint(idk)));
}
}
}
return fps;
}**/
public boolean resourceSupportsOmemo(final Jid jid)
{
try
{
if (jid.hasResource())
{
return mOmemoManager.resourceSupportsOmemo(jid.asFullJidIfPossible());
}
else
{
return getFingerprints(jid.asBareJid(),true).size() > 0;
}
}
catch (Exception e) {
Log.w(TAG, "error checking if resource supports omemo, will check for local fingerprints: " + jid, e);
;
try {
mOmemoManager.requestDeviceListUpdateFor(jid.asBareJid());
//let's just check fingerprints instead
return getFingerprints(jid.asBareJid(), false).size() > 0;
}
catch (Exception e2)
{
Log.e(TAG, "error checking if resource supports omemo: " + jid, e2);
}
}
return false;
}
public void loadDeviceList (BareJid jid)
{
try {
mOmemoManager.requestDeviceListUpdateFor(jid);
// OmemoDeviceListElement deviceList = mOmemoService.getPubSubHelper().fetchDeviceList(jid);
}
catch (Exception e)
{
Log.w(TAG, "error fetching device list",e);
}
}
/**
public boolean allDevicesTrustDecided (BareJid jid)
{
CachedDeviceList l = mOmemoStore.loadCachedDeviceList(jid);
int ourId = mOmemoStore.loadOmemoDeviceId();
for (Integer deviceId : l.getActiveDevices())
{
OmemoDevice d = new OmemoDevice(jid, deviceId);
try {
mOmemoService.buildSessionFromOmemoBundle(d);
SignalOmemoSession s = (SignalOmemoSession) mOmemoStore.getOmemoSessionOf(d);
if(s.getIdentityKey() == null) {
//debug(TAG,"OMEMO Build session...");
mOmemoService.buildSessionFromOmemoBundle(d);
s = (SignalOmemoSession) mOmemoStore.getOmemoSessionOf(d);
//debug(TAG, "OMEMO Session built: " + jid.toString());
}
//if we have a device that is untrusted
if (!mOmemoStore.isDecidedOmemoIdentity(d, s.getIdentityKey())) {
return false;
}
} catch (Exception e) {
Log.w(TAG, "error getting device session",e);
}
}
return true;
}**/
public boolean trustOmemoDevice (BareJid jid, boolean isTrusted)
{
CachedDeviceList l = mOmemoStore.loadCachedDeviceList(jid);
for (Integer deviceId : l.getActiveDevices())
{
try {
OmemoDevice d = new OmemoDevice(jid, deviceId);
mOmemoService.buildSessionFromOmemoBundle(d);
SignalOmemoSession s = (SignalOmemoSession) mOmemoStore.getOmemoSessionOf(d);
if(s.getIdentityKey() == null) {
Log.d(TAG,"unable to find identity key for: " + jid + " deviceid:" + deviceId);
continue;
}
if (mOmemoStore.isDecidedOmemoIdentity(d, s.getIdentityKey())) {
if (mOmemoStore.isTrustedOmemoIdentity(d, s.getIdentityKey())) {
Log.d(TAG, jid.toString() + " Status: Trusted");
} else {
Log.d(TAG,jid.toString() + " Status: Untrusted");
}
}
else {
if (s.getIdentityKey() == null)
{
Log.w(TAG, jid.toString() + " can't trust, identity key is null");
}
else {
if (isTrusted) {
mOmemoStore.trustOmemoIdentity(d, s.getIdentityKey());
Log.d(TAG, jid.toString() + " New Status: Trusted");
} else {
mOmemoStore.distrustOmemoIdentity(d, s.getIdentityKey());
Log.d(TAG, jid.toString() + " New Status: Untrusted");
}
}
}
} catch (Exception e) {
Log.w(TAG, "error getting device session",e);
}
}
return true;
}
}