Serviceless rewrite, part 1
Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
@@ -21,38 +21,38 @@ enum Attribute {
|
||||
PRIVATE_KEY("PrivateKey"),
|
||||
PUBLIC_KEY("PublicKey");
|
||||
|
||||
private static final Map<String, Attribute> map;
|
||||
private static final Map<String, Attribute> KEY_MAP;
|
||||
private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\\s|=");
|
||||
|
||||
static {
|
||||
map = new HashMap<>(Attribute.values().length);
|
||||
for (final Attribute key : Attribute.values())
|
||||
map.put(key.getToken(), key);
|
||||
KEY_MAP = new HashMap<>(Attribute.values().length);
|
||||
for (final Attribute key : Attribute.values()) {
|
||||
KEY_MAP.put(key.token, key);
|
||||
}
|
||||
}
|
||||
|
||||
public static Attribute match(final String line) {
|
||||
return map.get(line.split("\\s|=")[0]);
|
||||
}
|
||||
|
||||
private final String token;
|
||||
private final Pattern pattern;
|
||||
private final String token;
|
||||
|
||||
Attribute(final String token) {
|
||||
pattern = Pattern.compile(token + "\\s*=\\s*(\\S.*)");
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String composeWith(final String value) {
|
||||
return token + " = " + value + "\n";
|
||||
public static Attribute match(final CharSequence line) {
|
||||
return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0]);
|
||||
}
|
||||
|
||||
public String composeWith(final Object value) {
|
||||
return String.format("%s = %s%n", token, value);
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String parseFrom(final String line) {
|
||||
public String parse(final CharSequence line) {
|
||||
final Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.matches())
|
||||
return matcher.group(1);
|
||||
return null;
|
||||
return matcher.matches() ? matcher.group(1) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.databinding.Observable;
|
||||
import android.databinding.ObservableArrayList;
|
||||
import android.databinding.ObservableList;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.wireguard.android.BR;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a wg-quick configuration file, its name, and its connection state.
|
||||
*/
|
||||
|
||||
public class Config extends BaseObservable
|
||||
implements Comparable<Config>, Copyable<Config>, Observable, Parcelable {
|
||||
public static final Parcelable.Creator<Config> CREATOR = new Parcelable.Creator<Config>() {
|
||||
public class Config extends BaseObservable implements Parcelable {
|
||||
public static final Creator<Config> CREATOR = new Creator<Config>() {
|
||||
@Override
|
||||
public Config createFromParcel(final Parcel in) {
|
||||
return new Config(in);
|
||||
@@ -37,104 +28,22 @@ public class Config extends BaseObservable
|
||||
return new Config[size];
|
||||
}
|
||||
};
|
||||
public static final int NAME_MAX_LENGTH = 16;
|
||||
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9_=+.-]{1,16}$");
|
||||
|
||||
public static boolean isNameValid(final String name) {
|
||||
return name.length() <= NAME_MAX_LENGTH && PATTERN.matcher(name).matches();
|
||||
}
|
||||
|
||||
private final Interface iface;
|
||||
private boolean isEnabled;
|
||||
private boolean isPrimary;
|
||||
private String name;
|
||||
private final Interface interfaceSection;
|
||||
private final ObservableList<Peer> peers = new ObservableArrayList<>();
|
||||
|
||||
public Config() {
|
||||
iface = new Interface();
|
||||
interfaceSection = new Interface();
|
||||
}
|
||||
|
||||
protected Config(final Parcel in) {
|
||||
iface = in.readParcelable(Interface.class.getClassLoader());
|
||||
name = in.readString();
|
||||
// The flattened peers must be recreated to associate them with this config.
|
||||
final List<Peer> flattenedPeers = new LinkedList<>();
|
||||
in.readTypedList(flattenedPeers, Peer.CREATOR);
|
||||
for (final Peer peer : flattenedPeers)
|
||||
addPeer(peer);
|
||||
private Config(final Parcel in) {
|
||||
interfaceSection = in.readParcelable(Interface.class.getClassLoader());
|
||||
in.readTypedList(peers, Peer.CREATOR);
|
||||
}
|
||||
|
||||
public Peer addPeer() {
|
||||
final Peer peer = new Peer(this);
|
||||
peers.add(peer);
|
||||
return peer;
|
||||
}
|
||||
|
||||
private Peer addPeer(final Peer peer) {
|
||||
final Peer copy = peer.copy(this);
|
||||
peers.add(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final Config config) {
|
||||
return getName().compareTo(config.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config copy() {
|
||||
final Config copy = new Config();
|
||||
copy.copyFrom(this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(final Config source) {
|
||||
if (source != null) {
|
||||
iface.copyFrom(source.iface);
|
||||
name = source.name;
|
||||
peers.clear();
|
||||
for (final Peer peer : source.peers)
|
||||
addPeer(peer);
|
||||
} else {
|
||||
iface.copyFrom(null);
|
||||
name = null;
|
||||
peers.clear();
|
||||
}
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Interface getInterface() {
|
||||
return iface;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ObservableList<Peer> getPeers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
@Bindable
|
||||
public boolean isPrimary() {
|
||||
return isPrimary;
|
||||
}
|
||||
|
||||
public void parseFrom(final InputStream stream)
|
||||
public static Config from(final InputStream stream)
|
||||
throws IOException {
|
||||
peers.clear();
|
||||
final Config config = new Config();
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
||||
Peer currentPeer = null;
|
||||
@@ -147,10 +56,11 @@ public class Config extends BaseObservable
|
||||
currentPeer = null;
|
||||
inInterfaceSection = true;
|
||||
} else if ("[Peer]".equals(line)) {
|
||||
currentPeer = addPeer();
|
||||
currentPeer = new Peer();
|
||||
config.peers.add(currentPeer);
|
||||
inInterfaceSection = false;
|
||||
} else if (inInterfaceSection) {
|
||||
iface.parse(line);
|
||||
config.interfaceSection.parse(line);
|
||||
} else if (currentPeer != null) {
|
||||
currentPeer.parse(line);
|
||||
} else {
|
||||
@@ -161,28 +71,25 @@ public class Config extends BaseObservable
|
||||
throw new IllegalArgumentException("Could not find any config information");
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setIsEnabled(final boolean isEnabled) {
|
||||
this.isEnabled = isEnabled;
|
||||
notifyPropertyChanged(BR.enabled);
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setIsPrimary(final boolean isPrimary) {
|
||||
this.isPrimary = isPrimary;
|
||||
notifyPropertyChanged(BR.primary);
|
||||
public Interface getInterface() {
|
||||
return interfaceSection;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
if (name != null && !name.isEmpty() && !isNameValid(name))
|
||||
throw new IllegalArgumentException();
|
||||
this.name = name;
|
||||
notifyPropertyChanged(BR.name);
|
||||
public ObservableList<Peer> getPeers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder().append(iface);
|
||||
final StringBuilder sb = new StringBuilder().append(interfaceSection);
|
||||
for (final Peer peer : peers)
|
||||
sb.append('\n').append(peer);
|
||||
return sb.toString();
|
||||
@@ -190,8 +97,7 @@ public class Config extends BaseObservable
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel dest, final int flags) {
|
||||
dest.writeParcelable(iface, flags);
|
||||
dest.writeString(name);
|
||||
dest.writeParcelable(interfaceSection, flags);
|
||||
dest.writeTypedList(peers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.wireguard.config;
|
||||
|
||||
/**
|
||||
* Interface for classes that can perform a deep copy of their objects.
|
||||
*/
|
||||
|
||||
public interface Copyable<T> {
|
||||
T copy();
|
||||
void copyFrom(T source);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.wireguard.config;
|
||||
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.databinding.Observable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -14,10 +13,8 @@ import com.wireguard.crypto.Keypair;
|
||||
* Represents the configuration for a WireGuard interface (an [Interface] block).
|
||||
*/
|
||||
|
||||
public class Interface extends BaseObservable
|
||||
implements Copyable<Interface>, Observable, Parcelable {
|
||||
public static final Parcelable.Creator<Interface> CREATOR
|
||||
= new Parcelable.Creator<Interface>() {
|
||||
public class Interface extends BaseObservable implements Parcelable {
|
||||
public static final Creator<Interface> CREATOR = new Creator<Interface>() {
|
||||
@Override
|
||||
public Interface createFromParcel(final Parcel in) {
|
||||
return new Interface(in);
|
||||
@@ -31,8 +28,8 @@ public class Interface extends BaseObservable
|
||||
|
||||
private String address;
|
||||
private String dns;
|
||||
private String listenPort;
|
||||
private Keypair keypair;
|
||||
private String listenPort;
|
||||
private String mtu;
|
||||
private String privateKey;
|
||||
|
||||
@@ -40,7 +37,7 @@ public class Interface extends BaseObservable
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
protected Interface(final Parcel in) {
|
||||
private Interface(final Parcel in) {
|
||||
address = in.readString();
|
||||
dns = in.readString();
|
||||
listenPort = in.readString();
|
||||
@@ -48,31 +45,6 @@ public class Interface extends BaseObservable
|
||||
setPrivateKey(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Interface copy() {
|
||||
final Interface copy = new Interface();
|
||||
copy.copyFrom(this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(final Interface source) {
|
||||
if (source != null) {
|
||||
address = source.address;
|
||||
dns = source.dns;
|
||||
listenPort = source.listenPort;
|
||||
mtu = source.mtu;
|
||||
setPrivateKey(source.privateKey);
|
||||
} else {
|
||||
address = null;
|
||||
dns = null;
|
||||
listenPort = null;
|
||||
mtu = null;
|
||||
setPrivateKey(null);
|
||||
}
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -118,15 +90,15 @@ public class Interface extends BaseObservable
|
||||
public void parse(final String line) {
|
||||
final Attribute key = Attribute.match(line);
|
||||
if (key == Attribute.ADDRESS)
|
||||
setAddress(key.parseFrom(line));
|
||||
setAddress(key.parse(line));
|
||||
else if (key == Attribute.DNS)
|
||||
setDns(key.parseFrom(line));
|
||||
setDns(key.parse(line));
|
||||
else if (key == Attribute.LISTEN_PORT)
|
||||
setListenPort(key.parseFrom(line));
|
||||
setListenPort(key.parse(line));
|
||||
else if (key == Attribute.MTU)
|
||||
setMtu(key.parseFrom(line));
|
||||
setMtu(key.parse(line));
|
||||
else if (key == Attribute.PRIVATE_KEY)
|
||||
setPrivateKey(key.parseFrom(line));
|
||||
setPrivateKey(key.parse(line));
|
||||
else
|
||||
throw new IllegalArgumentException(line);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.wireguard.config;
|
||||
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.databinding.Observable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -12,8 +11,8 @@ import com.android.databinding.library.baseAdapters.BR;
|
||||
* Represents the configuration for a WireGuard peer (a [Peer] block).
|
||||
*/
|
||||
|
||||
public class Peer extends BaseObservable implements Copyable<Peer>, Observable, Parcelable {
|
||||
public static final Parcelable.Creator<Peer> CREATOR = new Parcelable.Creator<Peer>() {
|
||||
public class Peer extends BaseObservable implements Parcelable {
|
||||
public static final Creator<Peer> CREATOR = new Creator<Peer>() {
|
||||
@Override
|
||||
public Peer createFromParcel(final Parcel in) {
|
||||
return new Peer(in);
|
||||
@@ -26,44 +25,25 @@ public class Peer extends BaseObservable implements Copyable<Peer>, Observable,
|
||||
};
|
||||
|
||||
private String allowedIPs;
|
||||
private final Config config;
|
||||
private String endpoint;
|
||||
private String persistentKeepalive;
|
||||
private String preSharedKey;
|
||||
private String publicKey;
|
||||
|
||||
public Peer(final Config config) {
|
||||
this.config = config;
|
||||
public Peer() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
protected Peer(final Parcel in) {
|
||||
private Peer(final Parcel in) {
|
||||
allowedIPs = in.readString();
|
||||
config = null;
|
||||
endpoint = in.readString();
|
||||
persistentKeepalive = in.readString();
|
||||
preSharedKey = in.readString();
|
||||
publicKey = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Peer copy() {
|
||||
return copy(config);
|
||||
}
|
||||
|
||||
public Peer copy(final Config config) {
|
||||
final Peer copy = new Peer(config);
|
||||
copy.copyFrom(this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(final Peer source) {
|
||||
allowedIPs = source.allowedIPs;
|
||||
endpoint = source.endpoint;
|
||||
persistentKeepalive = source.persistentKeepalive;
|
||||
preSharedKey = source.preSharedKey;
|
||||
publicKey = source.publicKey;
|
||||
notifyChange();
|
||||
public static Peer newInstance() {
|
||||
return new Peer();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,24 +79,19 @@ public class Peer extends BaseObservable implements Copyable<Peer>, Observable,
|
||||
public void parse(final String line) {
|
||||
final Attribute key = Attribute.match(line);
|
||||
if (key == Attribute.ALLOWED_IPS)
|
||||
setAllowedIPs(key.parseFrom(line));
|
||||
setAllowedIPs(key.parse(line));
|
||||
else if (key == Attribute.ENDPOINT)
|
||||
setEndpoint(key.parseFrom(line));
|
||||
setEndpoint(key.parse(line));
|
||||
else if (key == Attribute.PERSISTENT_KEEPALIVE)
|
||||
setPersistentKeepalive(key.parseFrom(line));
|
||||
setPersistentKeepalive(key.parse(line));
|
||||
else if (key == Attribute.PRESHARED_KEY)
|
||||
setPreSharedKey(key.parseFrom(line));
|
||||
setPreSharedKey(key.parse(line));
|
||||
else if (key == Attribute.PUBLIC_KEY)
|
||||
setPublicKey(key.parseFrom(line));
|
||||
setPublicKey(key.parse(line));
|
||||
else
|
||||
throw new IllegalArgumentException(line);
|
||||
}
|
||||
|
||||
public void removeSelf() {
|
||||
if (!config.getPeers().remove(this))
|
||||
throw new IllegalStateException("This peer was already removed from its config");
|
||||
}
|
||||
|
||||
public void setAllowedIPs(String allowedIPs) {
|
||||
if (allowedIPs != null && allowedIPs.isEmpty())
|
||||
allowedIPs = null;
|
||||
|
||||
Reference in New Issue
Block a user