Use validation instead of two-way binding
This is insane, but it appears to be working. We essentially store things in a separate class for editing, and then commit it back at a given time. This business with onViewStateRestored in both TunnelEditorFragment and in TunnelDetailFragment is buggy and likely wrong. In general TunnelEditorFragment should probably be rewritten. The relationship with the changed name is not clear. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
693228985d
commit
63071f57b7
@ -10,6 +10,7 @@ import android.view.ViewGroup;
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
import com.wireguard.config.Config;
|
||||
|
||||
/**
|
||||
* Fragment that shows details about a specific tunnel.
|
||||
@ -18,6 +19,7 @@ import com.wireguard.android.model.Tunnel;
|
||||
public class TunnelDetailFragment extends BaseFragment {
|
||||
private TunnelDetailFragmentBinding binding;
|
||||
private boolean isViewStateRestored;
|
||||
private String originalName;
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
@ -45,16 +47,34 @@ public class TunnelDetailFragment extends BaseFragment {
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
private void onConfigLoaded(Config config) {
|
||||
binding.setConfig(new Config.Observable(config, originalName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
|
||||
if (binding != null && isViewStateRestored)
|
||||
if (binding != null && isViewStateRestored) {
|
||||
binding.setTunnel(newTunnel);
|
||||
if (newTunnel == null)
|
||||
binding.setConfig(null);
|
||||
else {
|
||||
originalName = newTunnel.getName();
|
||||
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewStateRestored(final Bundle savedInstanceState) {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
binding.setTunnel(getSelectedTunnel());
|
||||
Tunnel tunnel = getSelectedTunnel();
|
||||
binding.setTunnel(tunnel);
|
||||
if (tunnel == null)
|
||||
binding.setConfig(null);
|
||||
else {
|
||||
originalName = tunnel.getName();
|
||||
tunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
}
|
||||
isViewStateRestored = true;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.wireguard.android.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.databinding.ObservableField;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@ -31,11 +30,9 @@ import com.wireguard.config.Config;
|
||||
|
||||
public class TunnelEditorFragment extends BaseFragment {
|
||||
private static final String KEY_LOCAL_CONFIG = "local_config";
|
||||
private static final String KEY_LOCAL_NAME = "local_name";
|
||||
private static final String KEY_ORIGINAL_NAME = "original_name";
|
||||
private static final String TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName();
|
||||
|
||||
private final ObservableField<String> localName = new ObservableField<>("");
|
||||
private TunnelEditorFragmentBinding binding;
|
||||
private boolean isViewStateRestored;
|
||||
private Config localConfig = new Config();
|
||||
@ -56,7 +53,7 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
private void onConfigLoaded(final Config config) {
|
||||
localConfig = copyParcelable(config);
|
||||
if (binding != null && isViewStateRestored)
|
||||
binding.setConfig(localConfig);
|
||||
binding.setConfig(new Config.Observable(localConfig, originalName));
|
||||
}
|
||||
|
||||
private void onConfigSaved(@SuppressWarnings("unused") final Config config,
|
||||
@ -82,20 +79,17 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
localConfig = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG);
|
||||
localName.set(savedInstanceState.getString(KEY_LOCAL_NAME));
|
||||
originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME);
|
||||
}
|
||||
// Erase the remains of creating or editing a different tunnel.
|
||||
if (getSelectedTunnel() != null && !getSelectedTunnel().getName().equals(originalName)) {
|
||||
// The config must be loaded asynchronously since it's not an observable property.
|
||||
localConfig = null;
|
||||
getSelectedTunnel().getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
originalName = getSelectedTunnel().getName();
|
||||
localName.set(originalName);
|
||||
getSelectedTunnel().getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
} else if (getSelectedTunnel() == null && originalName != null) {
|
||||
localConfig = new Config();
|
||||
originalName = null;
|
||||
localName.set("");
|
||||
}
|
||||
localTunnel = getSelectedTunnel();
|
||||
setHasOptionsMenu(true);
|
||||
@ -147,14 +141,26 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_action_save:
|
||||
final Tunnel selectedTunnel = getSelectedTunnel();
|
||||
if (localConfig != null) {
|
||||
try {
|
||||
binding.getConfig().commitData(localConfig);
|
||||
} catch (Exception e) {
|
||||
final String error = ExceptionLoggers.unwrap(e).getMessage();
|
||||
final String message = getString(R.string.config_save_error, localTunnel.getName(), error);
|
||||
Log.e(TAG, message, e);
|
||||
final CoordinatorLayout container = binding.mainContainer;
|
||||
Snackbar.make(container, error, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (selectedTunnel == null) {
|
||||
Log.d(TAG, "Attempting to create new tunnel " + localName.get());
|
||||
Log.d(TAG, "Attempting to create new tunnel " + binding.getConfig().getName());
|
||||
final TunnelManager manager = Application.getComponent().getTunnelManager();
|
||||
manager.create(localName.get(), localConfig)
|
||||
manager.create(binding.getConfig().getName(), localConfig)
|
||||
.whenComplete(this::onTunnelCreated);
|
||||
} else if (!selectedTunnel.getName().equals(localName.get())) {
|
||||
Log.d(TAG, "Attempting to rename tunnel to " + localName.get());
|
||||
selectedTunnel.setName(localName.get())
|
||||
} else if (!selectedTunnel.getName().equals(binding.getConfig().getName())) {
|
||||
Log.d(TAG, "Attempting to rename tunnel to " + binding.getConfig().getName());
|
||||
selectedTunnel.setName(binding.getConfig().getName())
|
||||
.whenComplete(this::onTunnelRenamed);
|
||||
} else if (localConfig != null) {
|
||||
Log.d(TAG, "Attempting to save config of " + selectedTunnel.getName());
|
||||
@ -170,7 +176,6 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
@Override
|
||||
public void onSaveInstanceState(final Bundle outState) {
|
||||
outState.putParcelable(KEY_LOCAL_CONFIG, localConfig);
|
||||
outState.putString(KEY_LOCAL_NAME, localName.get());
|
||||
outState.putString(KEY_ORIGINAL_NAME, originalName);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
@ -181,15 +186,13 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
if (newTunnel != null) {
|
||||
// The config must be loaded asynchronously since it's not an observable property.
|
||||
localConfig = null;
|
||||
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
originalName = newTunnel.getName();
|
||||
localName.set(originalName);
|
||||
newTunnel.getConfigAsync().thenAccept(this::onConfigLoaded);
|
||||
} else {
|
||||
localConfig = new Config();
|
||||
if (binding != null && isViewStateRestored)
|
||||
binding.setConfig(localConfig);
|
||||
binding.setConfig(new Config.Observable(localConfig, ""));
|
||||
originalName = null;
|
||||
localName.set("");
|
||||
}
|
||||
localTunnel = newTunnel;
|
||||
}
|
||||
@ -234,8 +237,9 @@ public class TunnelEditorFragment extends BaseFragment {
|
||||
@Override
|
||||
public void onViewStateRestored(final Bundle savedInstanceState) {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
binding.setConfig(localConfig);
|
||||
binding.setName(localName);
|
||||
if (localConfig == null)
|
||||
localConfig = new Config();
|
||||
binding.setConfig(new Config.Observable(localConfig, originalName));
|
||||
isViewStateRestored = true;
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ enum Attribute {
|
||||
}
|
||||
|
||||
public static String[] stringToList(final String string) {
|
||||
if (string == null)
|
||||
return new String[0];
|
||||
return string.trim().split("\\s*,\\s*");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.wireguard.config;
|
||||
|
||||
import com.android.databinding.library.baseAdapters.BR;
|
||||
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.databinding.ObservableArrayList;
|
||||
import android.databinding.ObservableList;
|
||||
import android.os.Parcel;
|
||||
@ -11,12 +14,14 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a wg-quick configuration file, its name, and its connection state.
|
||||
*/
|
||||
|
||||
public class Config extends BaseObservable implements Parcelable {
|
||||
public class Config implements Parcelable {
|
||||
public static final Creator<Config> CREATOR = new Creator<Config>() {
|
||||
@Override
|
||||
public Config createFromParcel(final Parcel in) {
|
||||
@ -29,8 +34,59 @@ public class Config extends BaseObservable implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static class Observable extends BaseObservable {
|
||||
private String name;
|
||||
private Interface.Observable observableInterface;
|
||||
private ObservableList<Peer.Observable> observablePeers;
|
||||
|
||||
|
||||
public Observable(Config parent, String name) {
|
||||
this.name = name;
|
||||
loadData(parent);
|
||||
}
|
||||
|
||||
public void loadData(Config parent) {
|
||||
this.observableInterface = new Interface.Observable(parent.interfaceSection);
|
||||
this.observablePeers = new ObservableArrayList<>();
|
||||
for (Peer peer : parent.getPeers())
|
||||
this.observablePeers.add(new Peer.Observable(peer));
|
||||
}
|
||||
|
||||
public void commitData(Config parent) {
|
||||
this.observableInterface.commitData(parent.interfaceSection);
|
||||
List<Peer> newPeers = new ArrayList<>(this.observablePeers.size());
|
||||
for (Peer.Observable observablePeer : this.observablePeers) {
|
||||
Peer peer = new Peer();
|
||||
observablePeer.commitData(peer);
|
||||
newPeers.add(peer);
|
||||
}
|
||||
parent.peers = newPeers;
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
notifyPropertyChanged(BR.name);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public Interface.Observable getInterfaceSection() {
|
||||
return observableInterface;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public ObservableList<Peer.Observable> getPeers() {
|
||||
return observablePeers;
|
||||
}
|
||||
}
|
||||
|
||||
private final Interface interfaceSection;
|
||||
private final ObservableList<Peer> peers = new ObservableArrayList<>();
|
||||
private List<Peer> peers = new ArrayList<>();
|
||||
|
||||
public Config() {
|
||||
interfaceSection = new Interface();
|
||||
@ -83,7 +139,7 @@ public class Config extends BaseObservable implements Parcelable {
|
||||
return interfaceSection;
|
||||
}
|
||||
|
||||
public ObservableList<Peer> getPeers() {
|
||||
public List<Peer> getPeers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import android.os.Parcelable;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class IPCidr implements Parcelable {
|
||||
InetAddress address;
|
||||
|
@ -10,7 +10,6 @@ import com.wireguard.crypto.KeyEncoding;
|
||||
import com.wireguard.crypto.Keypair;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -18,7 +17,7 @@ import java.util.List;
|
||||
* Represents the configuration for a WireGuard interface (an [Interface] block).
|
||||
*/
|
||||
|
||||
public class Interface extends BaseObservable implements Parcelable {
|
||||
public class Interface implements Parcelable {
|
||||
public static final Creator<Interface> CREATOR = new Creator<Interface>() {
|
||||
@Override
|
||||
public Interface createFromParcel(final Parcel in) {
|
||||
@ -31,12 +30,114 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static class Observable extends BaseObservable {
|
||||
private String addresses;
|
||||
private String dnses;
|
||||
private String publicKey;
|
||||
private String privateKey;
|
||||
private String listenPort;
|
||||
private String mtu;
|
||||
|
||||
public Observable(Interface parent) {
|
||||
loadData(parent);
|
||||
}
|
||||
|
||||
public void loadData(Interface parent) {
|
||||
this.addresses = parent.getAddressString();
|
||||
this.dnses = parent.getDnsString();
|
||||
this.publicKey = parent.getPublicKey();
|
||||
this.privateKey = parent.getPrivateKey();
|
||||
this.listenPort = parent.getListenPortString();
|
||||
this.mtu = parent.getMtuString();
|
||||
}
|
||||
|
||||
public void commitData(Interface parent) {
|
||||
parent.setAddressString(this.addresses);
|
||||
parent.setDnsString(this.dnses);
|
||||
parent.setPrivateKey(this.privateKey);
|
||||
parent.setListenPortString(this.listenPort);
|
||||
parent.setMtuString(this.mtu);
|
||||
loadData(parent);
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setAddresses(String addresses) {
|
||||
this.addresses = addresses;
|
||||
notifyPropertyChanged(BR.addresses);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getDnses() {
|
||||
return dnses;
|
||||
}
|
||||
|
||||
public void setDnses(String dnses) {
|
||||
this.dnses = dnses;
|
||||
notifyPropertyChanged(BR.dnses);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
|
||||
try {
|
||||
this.publicKey = new Keypair(privateKey).getPublicKey();
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
this.publicKey = "";
|
||||
}
|
||||
|
||||
notifyPropertyChanged(BR.privateKey);
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
}
|
||||
|
||||
public void generateKeypair() {
|
||||
Keypair keypair = new Keypair();
|
||||
privateKey = keypair.getPrivateKey();
|
||||
publicKey = keypair.getPublicKey();
|
||||
notifyPropertyChanged(BR.privateKey);
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
public void setListenPort(String listenPort) {
|
||||
this.listenPort = listenPort;
|
||||
notifyPropertyChanged(BR.listenPort);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getMtu() {
|
||||
return mtu;
|
||||
}
|
||||
|
||||
public void setMtu(String mtu) {
|
||||
this.mtu = mtu;
|
||||
notifyPropertyChanged(BR.mtu);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IPCidr> addressList;
|
||||
private List<InetAddress> dnsList;
|
||||
private Keypair keypair;
|
||||
private int listenPort;
|
||||
private int mtu;
|
||||
private String privateKey;
|
||||
|
||||
public Interface() {
|
||||
addressList = new LinkedList<>();
|
||||
@ -63,76 +164,63 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void generateKeypair() {
|
||||
keypair = new Keypair();
|
||||
privateKey = keypair.getPrivateKey();
|
||||
notifyPropertyChanged(BR.privateKey);
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getAddressString() {
|
||||
private String getAddressString() {
|
||||
if (addressList.isEmpty())
|
||||
return null;
|
||||
return Attribute.listToString(addressList);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public IPCidr[] getAddresses() {
|
||||
return addressList.toArray(new IPCidr[addressList.size()]);
|
||||
}
|
||||
|
||||
public List<String> getDnsStrings() {
|
||||
private List<String> getDnsStrings() {
|
||||
List<String> strings = new LinkedList<>();
|
||||
for (final InetAddress addr : dnsList)
|
||||
strings.add(addr.getHostAddress());
|
||||
return strings;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getDnsString() {
|
||||
private String getDnsString() {
|
||||
if (dnsList.isEmpty())
|
||||
return null;
|
||||
return Attribute.listToString(getDnsStrings());
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public InetAddress[] getDnses() {
|
||||
return dnsList.toArray(new InetAddress[dnsList.size()]);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public int getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getListenPortString() {
|
||||
private String getListenPortString() {
|
||||
if (listenPort == 0)
|
||||
return null;
|
||||
return new Integer(listenPort).toString();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public int getMtu() {
|
||||
return mtu;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getMtuString() {
|
||||
private String getMtuString() {
|
||||
if (mtu == 0)
|
||||
return null;
|
||||
return new Integer(mtu).toString();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
if (keypair == null)
|
||||
return null;
|
||||
return keypair.getPrivateKey();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPublicKey() {
|
||||
return keypair != null ? keypair.getPublicKey() : null;
|
||||
if (keypair == null)
|
||||
return null;
|
||||
return keypair.getPublicKey();
|
||||
}
|
||||
|
||||
public void parse(final String line) {
|
||||
@ -151,7 +239,7 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
throw new IllegalArgumentException(line);
|
||||
}
|
||||
|
||||
public void addAddresses(String[] addresses) {
|
||||
private void addAddresses(String[] addresses) {
|
||||
if (addresses != null && addresses.length > 0) {
|
||||
for (final String addr : addresses) {
|
||||
if (addr.isEmpty())
|
||||
@ -159,74 +247,55 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
this.addressList.add(new IPCidr(addr));
|
||||
}
|
||||
}
|
||||
notifyPropertyChanged(BR.addresses);
|
||||
notifyPropertyChanged(BR.addressString);
|
||||
|
||||
}
|
||||
|
||||
public void setAddressString(final String addressString) {
|
||||
private void setAddressString(final String addressString) {
|
||||
this.addressList.clear();
|
||||
addAddresses(Attribute.stringToList(addressString));
|
||||
}
|
||||
|
||||
public void addDnses(String[] dnses) {
|
||||
private void addDnses(String[] dnses) {
|
||||
if (dnses != null && dnses.length > 0) {
|
||||
for (final String dns : dnses) {
|
||||
this.dnsList.add(Attribute.parseIPString(dns));
|
||||
}
|
||||
}
|
||||
notifyPropertyChanged(BR.dnses);
|
||||
notifyPropertyChanged(BR.dnsString);
|
||||
|
||||
}
|
||||
|
||||
public void setDnsString(final String dnsString) {
|
||||
private void setDnsString(final String dnsString) {
|
||||
this.dnsList.clear();
|
||||
addDnses(Attribute.stringToList(dnsString));
|
||||
}
|
||||
|
||||
public void setListenPort(int listenPort) {
|
||||
private void setListenPort(int listenPort) {
|
||||
this.listenPort = listenPort;
|
||||
notifyPropertyChanged(BR.listenPort);
|
||||
notifyPropertyChanged(BR.listenPortString);
|
||||
}
|
||||
|
||||
public void setListenPortString(final String port) {
|
||||
private void setListenPortString(final String port) {
|
||||
if (port != null && !port.isEmpty())
|
||||
setListenPort(Integer.parseInt(port, 10));
|
||||
else
|
||||
setListenPort(0);
|
||||
}
|
||||
|
||||
public void setMtu(int mtu) {
|
||||
private void setMtu(int mtu) {
|
||||
this.mtu = mtu;
|
||||
notifyPropertyChanged(BR.mtu);
|
||||
notifyPropertyChanged(BR.mtuString);
|
||||
}
|
||||
|
||||
public void setMtuString(final String mtu) {
|
||||
private void setMtuString(final String mtu) {
|
||||
if (mtu != null && !mtu.isEmpty())
|
||||
setMtu(Integer.parseInt(mtu, 10));
|
||||
else
|
||||
setMtu(0);
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
private void setPrivateKey(String privateKey) {
|
||||
if (privateKey != null && privateKey.isEmpty())
|
||||
privateKey = null;
|
||||
this.privateKey = privateKey;
|
||||
if (privateKey != null && privateKey.length() == KeyEncoding.KEY_LENGTH_BASE64) {
|
||||
try {
|
||||
keypair = new Keypair(privateKey);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
keypair = null;
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
if (privateKey == null)
|
||||
keypair = null;
|
||||
}
|
||||
notifyPropertyChanged(BR.privateKey);
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
else
|
||||
keypair = new Keypair(privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -240,8 +309,8 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
sb.append(Attribute.LISTEN_PORT.composeWith(listenPort));
|
||||
if (mtu != 0)
|
||||
sb.append(Attribute.MTU.composeWith(mtu));
|
||||
if (privateKey != null)
|
||||
sb.append(Attribute.PRIVATE_KEY.composeWith(privateKey));
|
||||
if (keypair != null)
|
||||
sb.append(Attribute.PRIVATE_KEY.composeWith(keypair.getPrivateKey()));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -253,6 +322,6 @@ public class Interface extends BaseObservable implements Parcelable {
|
||||
dest.writeByteArray(addr.getAddress());
|
||||
dest.writeInt(listenPort);
|
||||
dest.writeInt(mtu);
|
||||
dest.writeString(privateKey);
|
||||
dest.writeString(keypair == null ? "" : keypair.getPrivateKey());
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.databinding.library.baseAdapters.BR;
|
||||
import com.wireguard.crypto.KeyEncoding;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetSocketAddress;
|
||||
@ -19,7 +20,7 @@ import java.util.List;
|
||||
* Represents the configuration for a WireGuard peer (a [Peer] block).
|
||||
*/
|
||||
|
||||
public class Peer extends BaseObservable implements Parcelable {
|
||||
public class Peer implements Parcelable {
|
||||
public static final Creator<Peer> CREATOR = new Creator<Peer>() {
|
||||
@Override
|
||||
public Peer createFromParcel(final Parcel in) {
|
||||
@ -32,6 +33,92 @@ public class Peer extends BaseObservable implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static class Observable extends BaseObservable {
|
||||
private String allowedIPs;
|
||||
private String endpoint;
|
||||
private String persistentKeepalive;
|
||||
private String preSharedKey;
|
||||
private String publicKey;
|
||||
|
||||
|
||||
public Observable(Peer parent) {
|
||||
loadData(parent);
|
||||
}
|
||||
public static Observable newInstance() {
|
||||
return new Observable(new Peer());
|
||||
}
|
||||
|
||||
public void loadData(Peer parent) {
|
||||
this.allowedIPs = parent.getAllowedIPsString();
|
||||
this.endpoint = parent.getEndpointString();
|
||||
this.persistentKeepalive = parent.getPersistentKeepaliveString();
|
||||
this.preSharedKey = parent.getPreSharedKey();
|
||||
this.publicKey = parent.getPublicKey();
|
||||
}
|
||||
|
||||
public void commitData(Peer parent) {
|
||||
parent.setAllowedIPsString(this.allowedIPs);
|
||||
parent.setEndpointString(this.endpoint);
|
||||
parent.setPersistentKeepaliveString(this.persistentKeepalive);
|
||||
parent.setPreSharedKey(this.preSharedKey);
|
||||
parent.setPublicKey(this.publicKey);
|
||||
if (parent.getPublicKey() == null)
|
||||
throw new IllegalArgumentException("Peer public key may not be empty");
|
||||
loadData(parent);
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getAllowedIPs() {
|
||||
return allowedIPs;
|
||||
}
|
||||
|
||||
public void setAllowedIPs(String allowedIPs) {
|
||||
this.allowedIPs = allowedIPs;
|
||||
notifyPropertyChanged(BR.allowedIPs);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
notifyPropertyChanged(BR.endpoint);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPersistentKeepalive() {
|
||||
return persistentKeepalive;
|
||||
}
|
||||
|
||||
public void setPersistentKeepalive(String persistentKeepalive) {
|
||||
this.persistentKeepalive = persistentKeepalive;
|
||||
notifyPropertyChanged(BR.persistentKeepalive);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPreSharedKey() {
|
||||
return preSharedKey;
|
||||
}
|
||||
|
||||
public void setPreSharedKey(String preSharedKey) {
|
||||
this.preSharedKey = preSharedKey;
|
||||
notifyPropertyChanged(BR.preSharedKey);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IPCidr> allowedIPsList;
|
||||
private InetSocketAddress endpoint;
|
||||
private int persistentKeepalive;
|
||||
@ -57,35 +144,27 @@ public class Peer extends BaseObservable implements Parcelable {
|
||||
publicKey = null;
|
||||
}
|
||||
|
||||
public static Peer newInstance() {
|
||||
return new Peer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Bindable
|
||||
public String getAllowedIPsString() {
|
||||
private String getAllowedIPsString() {
|
||||
if (allowedIPsList.isEmpty())
|
||||
return null;
|
||||
return Attribute.listToString(allowedIPsList);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public IPCidr[] getAllowedIPs() {
|
||||
return allowedIPsList.toArray(new IPCidr[allowedIPsList.size()]);
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public InetSocketAddress getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getEndpointString() {
|
||||
private String getEndpointString() {
|
||||
if (endpoint == null)
|
||||
return null;
|
||||
return String.format("%s:%d", endpoint.getHostString(), endpoint.getPort());
|
||||
@ -103,24 +182,20 @@ public class Peer extends BaseObservable implements Parcelable {
|
||||
return String.format("%s:%d", endpoint.getAddress().getHostAddress(), endpoint.getPort());
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public int getPersistentKeepalive() {
|
||||
return persistentKeepalive;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPersistentKeepaliveString() {
|
||||
private String getPersistentKeepaliveString() {
|
||||
if (persistentKeepalive == 0)
|
||||
return null;
|
||||
return new Integer(persistentKeepalive).toString();
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPreSharedKey() {
|
||||
return preSharedKey;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
@ -141,28 +216,24 @@ public class Peer extends BaseObservable implements Parcelable {
|
||||
throw new IllegalArgumentException(line);
|
||||
}
|
||||
|
||||
public void addAllowedIPs(String[] allowedIPs) {
|
||||
private void addAllowedIPs(String[] allowedIPs) {
|
||||
if (allowedIPs != null && allowedIPs.length > 0) {
|
||||
for (final String allowedIP : allowedIPs) {
|
||||
this.allowedIPsList.add(new IPCidr(allowedIP));
|
||||
}
|
||||
}
|
||||
notifyPropertyChanged(BR.allowedIPs);
|
||||
notifyPropertyChanged(BR.allowedIPsString);
|
||||
}
|
||||
|
||||
public void setAllowedIPsString(final String allowedIPsString) {
|
||||
private void setAllowedIPsString(final String allowedIPsString) {
|
||||
this.allowedIPsList.clear();
|
||||
addAllowedIPs(Attribute.stringToList(allowedIPsString));
|
||||
}
|
||||
|
||||
public void setEndpoint(InetSocketAddress endpoint) {
|
||||
private void setEndpoint(InetSocketAddress endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
notifyPropertyChanged(BR.endpoint);
|
||||
notifyPropertyChanged(BR.endpointString);
|
||||
}
|
||||
|
||||
public void setEndpointString(final String endpoint) {
|
||||
private void setEndpointString(final String endpoint) {
|
||||
if (endpoint != null && !endpoint.isEmpty()) {
|
||||
InetSocketAddress constructedEndpoint;
|
||||
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
|
||||
@ -179,31 +250,31 @@ public class Peer extends BaseObservable implements Parcelable {
|
||||
setEndpoint(null);
|
||||
}
|
||||
|
||||
public void setPersistentKeepalive(int persistentKeepalive) {
|
||||
private void setPersistentKeepalive(int persistentKeepalive) {
|
||||
this.persistentKeepalive = persistentKeepalive;
|
||||
notifyPropertyChanged(BR.persistentKeepalive);
|
||||
notifyPropertyChanged(BR.persistentKeepaliveString);
|
||||
}
|
||||
|
||||
public void setPersistentKeepaliveString(String persistentKeepalive) {
|
||||
private void setPersistentKeepaliveString(String persistentKeepalive) {
|
||||
if (persistentKeepalive != null && !persistentKeepalive.isEmpty())
|
||||
setPersistentKeepalive(Integer.parseInt(persistentKeepalive, 10));
|
||||
else
|
||||
setPersistentKeepalive(0);
|
||||
}
|
||||
|
||||
public void setPreSharedKey(String preSharedKey) {
|
||||
private void setPreSharedKey(String preSharedKey) {
|
||||
if (preSharedKey != null && preSharedKey.isEmpty())
|
||||
preSharedKey = null;
|
||||
if (preSharedKey != null)
|
||||
KeyEncoding.keyFromBase64(preSharedKey);
|
||||
this.preSharedKey = preSharedKey;
|
||||
notifyPropertyChanged(BR.preSharedKey);
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
private void setPublicKey(String publicKey) {
|
||||
if (publicKey != null && publicKey.isEmpty())
|
||||
publicKey = null;
|
||||
if (publicKey != null)
|
||||
KeyEncoding.keyFromBase64(publicKey);
|
||||
this.publicKey = publicKey;
|
||||
notifyPropertyChanged(BR.publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -14,6 +14,10 @@
|
||||
<variable
|
||||
name="tunnel"
|
||||
type="com.wireguard.android.model.Tunnel" />
|
||||
|
||||
<variable
|
||||
name="config"
|
||||
type="com.wireguard.config.Config.Observable" />
|
||||
</data>
|
||||
|
||||
<ScrollView
|
||||
@ -92,7 +96,25 @@
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{tunnel.config.interface.publicKey}" />
|
||||
android:text="@{config.interfaceSection.publicKey}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/public_key_text"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/addresses_text"
|
||||
android:text="@string/addresses" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_text"
|
||||
style="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/addresses_label"
|
||||
android:contentDescription="@string/addresses"
|
||||
android:text="@{config.interfaceSection.addresses}" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -101,7 +123,7 @@
|
||||
android:layout_marginBottom="4dp"
|
||||
android:divider="@null"
|
||||
android:orientation="vertical"
|
||||
app:items="@{tunnel.config.peers}"
|
||||
app:items="@{config.peers}"
|
||||
app:layout="@{@layout/tunnel_detail_peer}"
|
||||
tools:ignore="UselessLeaf" />
|
||||
</LinearLayout>
|
||||
|
@ -5,13 +5,9 @@
|
||||
|
||||
<import type="com.wireguard.android.util.ClipboardUtils" />
|
||||
|
||||
<variable
|
||||
name="collection"
|
||||
type="android.databinding.ObservableList<com.wireguard.config.Peer>" />
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.wireguard.config.Peer" />
|
||||
type="com.wireguard.config.Peer.Observable" />
|
||||
</data>
|
||||
|
||||
<RelativeLayout
|
||||
@ -69,7 +65,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/allowed_ips_label"
|
||||
android:text="@{item.allowedIPsString}" />
|
||||
android:text="@{item.allowedIPs}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/endpoint_label"
|
||||
@ -86,6 +82,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/endpoint_label"
|
||||
android:text="@{item.endpointString}" />
|
||||
android:text="@{item.endpoint}" />
|
||||
</RelativeLayout>
|
||||
</layout>
|
||||
|
@ -15,11 +15,7 @@
|
||||
|
||||
<variable
|
||||
name="config"
|
||||
type="com.wireguard.config.Config" />
|
||||
|
||||
<variable
|
||||
name="name"
|
||||
type="android.databinding.ObservableField<String>" />
|
||||
type="com.wireguard.config.Config.Observable" />
|
||||
</data>
|
||||
|
||||
<com.commonsware.cwac.crossport.design.widget.CoordinatorLayout
|
||||
@ -71,7 +67,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/interface_name_label"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={name}"
|
||||
android:text="@={config.name}"
|
||||
app:filter="@{NameInputFilter.newInstance()}" />
|
||||
|
||||
<TextView
|
||||
@ -91,7 +87,7 @@
|
||||
android:layout_toStartOf="@+id/generate_private_key_button"
|
||||
android:contentDescription="@string/public_key_description"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={config.interface.privateKey}"
|
||||
android:text="@={config.interfaceSection.privateKey}"
|
||||
app:filter="@{KeyInputFilter.newInstance()}" />
|
||||
|
||||
<Button
|
||||
@ -101,7 +97,7 @@
|
||||
android:layout_alignBottom="@id/private_key_text"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_below="@+id/private_key_label"
|
||||
android:onClick="@{() -> config.interface.generateKeypair()}"
|
||||
android:onClick="@{() -> config.interfaceSection.generateKeypair()}"
|
||||
android:text="@string/generate" />
|
||||
|
||||
<TextView
|
||||
@ -124,7 +120,7 @@
|
||||
android:maxLines="1"
|
||||
android:contentDescription="@string/public_key_description"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.publicKey}" />
|
||||
android:text="@{config.interfaceSection.publicKey}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_label"
|
||||
@ -144,7 +140,7 @@
|
||||
android:layout_below="@+id/addresses_label"
|
||||
android:layout_toStartOf="@+id/listen_port_text"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={config.interface.addressString}" />
|
||||
android:text="@={config.interfaceSection.addresses}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/listen_port_label"
|
||||
@ -165,7 +161,7 @@
|
||||
android:layout_alignStart="@+id/generate_private_key_button"
|
||||
android:hint="@string/hint_random"
|
||||
android:inputType="number"
|
||||
android:text="@={config.interface.listenPortString}"
|
||||
android:text="@={config.interfaceSection.listenPort}"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
@ -186,7 +182,7 @@
|
||||
android:layout_below="@+id/dns_servers_label"
|
||||
android:layout_toStartOf="@+id/mtu_text"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={config.interface.dnsString}" />
|
||||
android:text="@={config.interfaceSection.dnses}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mtu_label"
|
||||
@ -207,7 +203,7 @@
|
||||
android:layout_alignStart="@+id/generate_private_key_button"
|
||||
android:hint="@string/hint_automatic"
|
||||
android:inputType="number"
|
||||
android:text="@={config.interface.mtuString}"
|
||||
android:text="@={config.interfaceSection.mtu}"
|
||||
android:textAlignment="center" />
|
||||
</RelativeLayout>
|
||||
|
||||
@ -226,7 +222,7 @@
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:onClick="@{() -> config.peers.add(Peer.newInstance())}"
|
||||
android:onClick="@{() -> config.peers.add(Peer.Observable.newInstance())}"
|
||||
android:text="@string/add_peer" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
<variable
|
||||
name="collection"
|
||||
type="android.databinding.ObservableList<com.wireguard.config.Peer>" />
|
||||
type="android.databinding.ObservableList<com.wireguard.config.Peer.Observable>" />
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.wireguard.config.Peer" />
|
||||
type="com.wireguard.config.Peer.Observable" />
|
||||
</data>
|
||||
|
||||
<RelativeLayout
|
||||
@ -96,7 +96,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/allowed_ips_label"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={item.allowedIPsString}" />
|
||||
android:text="@={item.allowedIPs}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/endpoint_label"
|
||||
@ -116,7 +116,7 @@
|
||||
android:layout_below="@+id/endpoint_label"
|
||||
android:layout_toStartOf="@+id/persistent_keepalive_text"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
android:text="@={item.endpointString}" />
|
||||
android:text="@={item.endpoint}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/persistent_keepalive_label"
|
||||
@ -136,7 +136,7 @@
|
||||
android:layout_alignStart="@+id/persistent_keepalive_label"
|
||||
android:hint="@string/hint_optional"
|
||||
android:inputType="number"
|
||||
android:text="@={item.persistentKeepaliveString}"
|
||||
android:text="@={item.persistentKeepalive}"
|
||||
android:textAlignment="center" />
|
||||
</RelativeLayout>
|
||||
</layout>
|
||||
|
Loading…
Reference in New Issue
Block a user