diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseComputerLink.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLink.java similarity index 65% rename from KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseComputerLink.java rename to KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLink.java index 2dc741f7..59d13e8b 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseComputerLink.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLink.java @@ -1,17 +1,26 @@ package org.kde.kdeconnect.Backends; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Base64; + import org.kde.kdeconnect.NetworkPackage; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; -public abstract class BaseComputerLink { +public abstract class BaseLink { private BaseLinkProvider linkProvider; private String deviceId; private ArrayList receivers = new ArrayList(); + protected PrivateKey privateKey; - protected BaseComputerLink(String deviceId, BaseLinkProvider linkProvider) { + protected BaseLink(String deviceId, BaseLinkProvider linkProvider) { this.linkProvider = linkProvider; this.deviceId = deviceId; } @@ -20,6 +29,10 @@ public abstract class BaseComputerLink { return deviceId; } + public void setPrivateKey(PrivateKey key) { + privateKey = key; + } + public BaseLinkProvider getLinkProvider() { return linkProvider; } @@ -45,5 +58,6 @@ public abstract class BaseComputerLink { //TO OVERRIDE public abstract boolean sendPackage(NetworkPackage np); + public abstract boolean sendPackageEncrypted(NetworkPackage np, PublicKey key); } diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLinkProvider.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLinkProvider.java index aadd7084..a755bc8c 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLinkProvider.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/BaseLinkProvider.java @@ -2,7 +2,6 @@ package org.kde.kdeconnect.Backends; import android.util.Log; -import org.kde.kdeconnect.Backends.BaseComputerLink; import org.kde.kdeconnect.NetworkPackage; import java.util.ArrayList; @@ -12,8 +11,8 @@ public abstract class BaseLinkProvider { private ArrayList connectionReceivers = new ArrayList(); public interface ConnectionReceiver { - public void onConnectionReceived(NetworkPackage identityPackage, BaseComputerLink link); - public void onConnectionLost(BaseComputerLink link); + public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link); + public void onConnectionLost(BaseLink link); } public void addConnectionReceiver(ConnectionReceiver cr) { @@ -25,13 +24,13 @@ public abstract class BaseLinkProvider { } //These two should be called when the provider links to a new computer - protected void connectionAccepted(NetworkPackage identityPackage, BaseComputerLink link) { + protected void connectionAccepted(NetworkPackage identityPackage, BaseLink link) { Log.i("LinkProvider", "connectionAccepted"); for(ConnectionReceiver cr : connectionReceivers) { cr.onConnectionReceived(identityPackage, link); } } - protected void connectionLost(BaseComputerLink link) { + protected void connectionLost(BaseLink link) { Log.i("LinkProvider", "connectionLost"); for(ConnectionReceiver cr : connectionReceivers) { cr.onConnectionLost(link); diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanComputerLink.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanComputerLink.java deleted file mode 100644 index ff645604..00000000 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanComputerLink.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.kde.kdeconnect.Backends.LanBackend; - -import android.util.Log; - -import org.apache.mina.core.session.IoSession; -import org.kde.kdeconnect.Backends.BaseComputerLink; -import org.kde.kdeconnect.Backends.BaseLinkProvider; -import org.kde.kdeconnect.NetworkPackage; - -public class LanComputerLink extends BaseComputerLink { - - private IoSession session = null; - - public void disconnect() { - Log.i("LanComputerLink","Disconnect: "+session.getRemoteAddress().toString()); - session.close(true); - } - - public LanComputerLink(IoSession session, String deviceId, BaseLinkProvider linkProvider) { - super(deviceId, linkProvider); - this.session = session; - } - - @Override - public boolean sendPackage(NetworkPackage np) { - if (session == null) { - Log.e("LanComputerLink","sendPackage failed: not yet connected"); - return false; - } else { - session.write(np.serialize()); - return true; - } - } - - public void injectNetworkPackage(NetworkPackage np) { - packageReceived(np); - } -} diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLink.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLink.java new file mode 100644 index 00000000..8eff723a --- /dev/null +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLink.java @@ -0,0 +1,70 @@ +package org.kde.kdeconnect.Backends.LanBackend; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Base64; +import android.util.Log; + +import org.apache.mina.core.session.IoSession; +import org.kde.kdeconnect.Backends.BaseLink; +import org.kde.kdeconnect.Backends.BaseLinkProvider; +import org.kde.kdeconnect.NetworkPackage; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; + +public class LanLink extends BaseLink { + + private IoSession session = null; + + public void disconnect() { + Log.i("LanLink","Disconnect: "+session.getRemoteAddress().toString()); + session.close(true); + } + + public LanLink(IoSession session, String deviceId, BaseLinkProvider linkProvider) { + super(deviceId, linkProvider); + this.session = session; + } + + @Override + public boolean sendPackage(NetworkPackage np) { + if (session == null) { + Log.e("LanLink","sendPackage failed: not yet connected"); + return false; + } else { + session.write(np.serialize()); + return true; + } + } + + @Override + public boolean sendPackageEncrypted(NetworkPackage np, PublicKey key) { + try { + np.encrypt(key); + return sendPackage(np); + } catch (Exception e) { + e.printStackTrace(); + Log.e("LanLink", "Encryption exception"); + } + return false; + } + + public void injectNetworkPackage(NetworkPackage np) { + + if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_ENCRYPTED)) { + + try { + np = np.decrypt(privateKey); + } catch(Exception e) { + e.printStackTrace(); + Log.e("onPackageReceived","Exception reading the key needed to decrypt the package"); + } + + } + + packageReceived(np); + } +} diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java index b453e033..f44cfa01 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java @@ -31,8 +31,8 @@ public class LanLinkProvider extends BaseLinkProvider { private final static int port = 1714; private Context context; - private HashMap visibleComputers = new HashMap(); - private HashMap nioSessions = new HashMap(); + private HashMap visibleComputers = new HashMap(); + private HashMap nioSessions = new HashMap(); private NioSocketAcceptor tcpAcceptor = null; private NioDatagramAcceptor udpAcceptor = null; @@ -41,7 +41,7 @@ public class LanLinkProvider extends BaseLinkProvider { @Override public void sessionClosed(IoSession session) throws Exception { - LanComputerLink brokenLink = nioSessions.remove(session.getId()); + LanLink brokenLink = nioSessions.remove(session.getId()); if (brokenLink != null) { connectionLost(brokenLink); brokenLink.disconnect(); @@ -62,14 +62,14 @@ public class LanLinkProvider extends BaseLinkProvider { String theMessage = (String) message; NetworkPackage np = NetworkPackage.unserialize(theMessage); - LanComputerLink prevLink = nioSessions.get(session.getId()); + LanLink prevLink = nioSessions.get(session.getId()); if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) { String myId = NetworkPackage.createIdentityPackage(context).getString("deviceId"); if (np.getString("deviceId").equals(myId)) { return; } - LanComputerLink link = new LanComputerLink(session, np.getString("deviceId"), LanLinkProvider.this); + LanLink link = new LanLink(session, np.getString("deviceId"), LanLinkProvider.this); nioSessions.put(session.getId(),link); addLink(np, link); } else { @@ -138,7 +138,7 @@ public class LanLinkProvider extends BaseLinkProvider { Log.i("LanLinkProvider", "Connection successful: " + session.isConnected()); - LanComputerLink link = new LanComputerLink(session, identityPackage.getString("deviceId"), LanLinkProvider.this); + LanLink link = new LanLink(session, identityPackage.getString("deviceId"), LanLinkProvider.this); NetworkPackage np2 = NetworkPackage.createIdentityPackage(context); link.sendPackage(np2); @@ -157,10 +157,10 @@ public class LanLinkProvider extends BaseLinkProvider { } }; - private void addLink(NetworkPackage identityPackage, LanComputerLink link) { + private void addLink(NetworkPackage identityPackage, LanLink link) { String deviceId = identityPackage.getString("deviceId"); Log.i("LanLinkProvider","addLink to "+deviceId); - LanComputerLink oldLink = visibleComputers.get(deviceId); + LanLink oldLink = visibleComputers.get(deviceId); visibleComputers.put(deviceId, link); connectionAccepted(identityPackage, link); if (oldLink != null) { diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackComputerLink.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackComputerLink.java deleted file mode 100644 index e1baa4a6..00000000 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackComputerLink.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.kde.kdeconnect.Backends.LoopbackBackend; - -import org.kde.kdeconnect.Backends.BaseComputerLink; -import org.kde.kdeconnect.Backends.BaseLinkProvider; -import org.kde.kdeconnect.NetworkPackage; - -public class LoopbackComputerLink extends BaseComputerLink { - - public LoopbackComputerLink(BaseLinkProvider linkProvider) { - super("loopback", linkProvider); - } - - @Override - public boolean sendPackage(NetworkPackage in) { - String s = in.serialize(); - NetworkPackage out= NetworkPackage.unserialize(s); - packageReceived(out); - return true; - } - -} diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java new file mode 100644 index 00000000..5ee31be7 --- /dev/null +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java @@ -0,0 +1,41 @@ +package org.kde.kdeconnect.Backends.LoopbackBackend; + +import android.util.Log; + +import org.kde.kdeconnect.Backends.BaseLink; +import org.kde.kdeconnect.Backends.BaseLinkProvider; +import org.kde.kdeconnect.NetworkPackage; + +import java.security.PublicKey; + +public class LoopbackLink extends BaseLink { + + public LoopbackLink(BaseLinkProvider linkProvider) { + super("loopback", linkProvider); + } + + @Override + public boolean sendPackage(NetworkPackage in) { + String s = in.serialize(); + NetworkPackage out= NetworkPackage.unserialize(s); + packageReceived(out); + return true; + } + + @Override + public boolean sendPackageEncrypted(NetworkPackage in, PublicKey key) { + try { + in.encrypt(key); + String s = in.serialize(); + NetworkPackage out= NetworkPackage.unserialize(s); + out.decrypt(privateKey); + packageReceived(out); + return true; + } catch(Exception e) { + e.printStackTrace(); + Log.e("LoopbackLink", "Encryption exception"); + return false; + } + + } +} diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java index 9385ab9c..766881b2 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLinkProvider.java @@ -27,7 +27,7 @@ public class LoopbackLinkProvider extends BaseLinkProvider { public void onNetworkChange() { NetworkPackage np = NetworkPackage.createIdentityPackage(context); - connectionAccepted(np, new LoopbackComputerLink(this)); + connectionAccepted(np, new LoopbackLink(this)); } diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/BackgroundService.java b/KdeConnect/src/main/java/org/kde/kdeconnect/BackgroundService.java index 5581fd0e..d21c7caf 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/BackgroundService.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/BackgroundService.java @@ -11,7 +11,7 @@ import android.preference.PreferenceManager; import android.util.Base64; import android.util.Log; -import org.kde.kdeconnect.Backends.BaseComputerLink; +import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider; import org.kde.kdeconnect.Backends.LoopbackBackend.LoopbackLinkProvider; @@ -81,7 +81,7 @@ public class BackgroundService extends Service { private BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() { @Override - public void onConnectionReceived(final NetworkPackage identityPackage, final BaseComputerLink link) { + public void onConnectionReceived(final NetworkPackage identityPackage, final BaseLink link) { Log.i("BackgroundService", "Connection accepted!"); @@ -104,7 +104,7 @@ public class BackgroundService extends Service { } @Override - public void onConnectionLost(BaseComputerLink link) { + public void onConnectionLost(BaseLink link) { Device d = devices.get(link.getDeviceId()); Log.i("onConnectionLost", "removeLink, deviceId: " + link.getDeviceId()); if (d != null) { diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Device.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Device.java index a9e29d3d..0ea450d6 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Device.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Device.java @@ -15,7 +15,7 @@ import android.support.v4.app.NotificationCompat; import android.util.Base64; import android.util.Log; -import org.kde.kdeconnect.Backends.BaseComputerLink; +import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.PluginFactory; import org.kde.kdeconnect.UserInterface.PairActivity; @@ -34,7 +34,7 @@ import java.util.Set; import java.util.Timer; import java.util.TimerTask; -public class Device implements BaseComputerLink.PackageReceiver { +public class Device implements BaseLink.PackageReceiver { private Context context; @@ -61,7 +61,7 @@ public class Device implements BaseComputerLink.PackageReceiver { private ArrayList pairingCallback = new ArrayList(); private Timer pairingTimer; - private ArrayList links = new ArrayList(); + private ArrayList links = new ArrayList(); private HashMap plugins = new HashMap(); private HashMap failedPlugins = new HashMap(); @@ -90,7 +90,7 @@ public class Device implements BaseComputerLink.PackageReceiver { } //Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet - Device(Context context, String deviceId, String name, BaseComputerLink dl) { + Device(Context context, String deviceId, String name, BaseLink dl) { settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE); //Log.e("Device","Constructor B"); @@ -255,15 +255,25 @@ public class Device implements BaseComputerLink.PackageReceiver { return !links.isEmpty(); } - public void addLink(BaseComputerLink link) { + public void addLink(BaseLink link) { links.add(link); + try { + SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context); + byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey", ""), 0); + PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); + link.setPrivateKey(privateKey); + } catch (Exception e) { + e.printStackTrace(); + Log.e("Device", "Exception reading our own private key"); //Should not happen + } + Log.i("Device","addLink "+link.getLinkProvider().getName()+" -> "+getName() + " active links: "+ links.size()); - Collections.sort(links, new Comparator() { + Collections.sort(links, new Comparator() { @Override - public int compare(BaseComputerLink o, BaseComputerLink o2) { + public int compare(BaseLink o, BaseLink o2) { return o2.getLinkProvider().getPriority() - o.getLinkProvider().getPriority(); } }); @@ -275,7 +285,7 @@ public class Device implements BaseComputerLink.PackageReceiver { } } - public void removeLink(BaseComputerLink link) { + public void removeLink(BaseLink link) { link.removePackageReceiver(this); links.remove(link); Log.i("Device","removeLink: "+link.getLinkProvider().getName() + " -> "+getName() + " active links: "+ links.size()); @@ -398,23 +408,6 @@ public class Device implements BaseComputerLink.PackageReceiver { Log.e("onPackageReceived","Device not paired, ignoring package!"); } else { - if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_ENCRYPTED)) { - - try { - //TODO: Do not read the key every time - SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context); - byte[] privateKeyBytes = Base64.decode(globalSettings.getString("privateKey",""), 0); - PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); - np = np.decrypt(privateKey); - } catch(Exception e) { - e.printStackTrace(); - Log.e("onPackageReceived","Exception reading the key needed to decrypt the package"); - } - - } else { - //TODO: The other side doesn't know that we are already paired, do something - Log.e("onPackageReceived","WARNING: Received unencrypted package from paired device!"); - } for (Plugin plugin : plugins.values()) { plugin.onPackageReceived(np); @@ -426,27 +419,26 @@ public class Device implements BaseComputerLink.PackageReceiver { public boolean sendPackage(final NetworkPackage np) { - if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired()) { - try { - np.encrypt(publicKey); - } catch(Exception e) { - e.printStackTrace(); - Log.e("Device","sendPackage exception - could not encrypt"); - } - } - new AsyncTask() { @Override protected Void doInBackground(Void... voids) { - for(BaseComputerLink link : links) { - //Log.e("sendPackage","Trying "+link.getLinkProvider().getName()); - if (link.sendPackage(np)) { - //Log.e("sent using", link.getLinkProvider().getName()); - return null; + + boolean useEncryption = (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired()); + + for(BaseLink link : links) { + + if (useEncryption) { + if (link.sendPackageEncrypted(np, publicKey)) return null; + } else { + if (link.sendPackage(np)) return null; } + } + Log.e("sendPackage","Error: Package could not be sent ("+links.size()+" links available)"); + return null; + } }.execute(); diff --git a/KdeConnect/src/main/java/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java b/KdeConnect/src/main/java/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java index b55e00b6..6389255c 100644 --- a/KdeConnect/src/main/java/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java +++ b/KdeConnect/src/main/java/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java @@ -13,8 +13,8 @@ import android.widget.SeekBar; import android.widget.Spinner; import android.widget.TextView; +import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.BackgroundService; -import org.kde.kdeconnect.Backends.BaseComputerLink; import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.NetworkPackage; @@ -121,12 +121,12 @@ public class MprisActivity extends Activity { BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() { @Override - public void onConnectionReceived(NetworkPackage identityPackage, BaseComputerLink link) { + public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link) { connectToPlugin(); } @Override - public void onConnectionLost(BaseComputerLink link) { + public void onConnectionLost(BaseLink link) { } };