mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-29 13:17:43 +00:00
Moved cryptography layer down from Device to Backend
Matching KDED structure
This commit is contained in:
parent
63f0458096
commit
e735e0ecf3
@ -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<PackageReceiver> receivers = new ArrayList<PackageReceiver>();
|
||||
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);
|
||||
|
||||
}
|
@ -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<ConnectionReceiver> connectionReceivers = new ArrayList<ConnectionReceiver>();
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -31,8 +31,8 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
private final static int port = 1714;
|
||||
|
||||
private Context context;
|
||||
private HashMap<String, LanComputerLink> visibleComputers = new HashMap<String, LanComputerLink>();
|
||||
private HashMap<Long, LanComputerLink> nioSessions = new HashMap<Long, LanComputerLink>();
|
||||
private HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
|
||||
private HashMap<Long, LanLink> nioSessions = new HashMap<Long, LanLink>();
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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> pairingCallback = new ArrayList<PairingCallback>();
|
||||
private Timer pairingTimer;
|
||||
|
||||
private ArrayList<BaseComputerLink> links = new ArrayList<BaseComputerLink>();
|
||||
private ArrayList<BaseLink> links = new ArrayList<BaseLink>();
|
||||
private HashMap<String, Plugin> plugins = new HashMap<String, Plugin>();
|
||||
private HashMap<String, Plugin> failedPlugins = new HashMap<String, Plugin>();
|
||||
|
||||
@ -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<BaseComputerLink>() {
|
||||
Collections.sort(links, new Comparator<BaseLink>() {
|
||||
@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<Void,Void,Void>() {
|
||||
@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();
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user