2017-07-29 13:08:54 +02:00
|
|
|
package com.wireguard.config;
|
|
|
|
|
2017-08-01 04:13:01 +02:00
|
|
|
import android.databinding.BaseObservable;
|
|
|
|
import android.databinding.Bindable;
|
|
|
|
import android.databinding.Observable;
|
2017-07-30 00:30:33 +02:00
|
|
|
import android.databinding.ObservableArrayList;
|
|
|
|
import android.databinding.ObservableList;
|
2017-08-16 08:06:05 +02:00
|
|
|
import android.support.annotation.NonNull;
|
2017-07-29 13:08:54 +02:00
|
|
|
|
2017-08-01 04:13:01 +02:00
|
|
|
import com.wireguard.android.BR;
|
|
|
|
|
2017-07-29 13:08:54 +02:00
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.InputStreamReader;
|
2017-07-30 00:30:33 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2017-08-13 14:24:03 +02:00
|
|
|
import java.util.regex.Pattern;
|
2017-07-29 13:08:54 +02:00
|
|
|
|
|
|
|
/**
|
2017-08-13 14:24:03 +02:00
|
|
|
* Represents a wg-quick configuration file, its name, and its connection state.
|
2017-07-29 13:08:54 +02:00
|
|
|
*/
|
|
|
|
|
2017-08-16 08:06:05 +02:00
|
|
|
public class Config extends BaseObservable
|
|
|
|
implements Comparable<Config>, Copyable<Config>, Observable {
|
2017-08-23 04:48:42 +02:00
|
|
|
public static final int NAME_MAX_LENGTH = 16;
|
2017-08-13 14:24:03 +02:00
|
|
|
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9_=+.-]{1,16}$");
|
|
|
|
|
|
|
|
private static boolean isNameValid(final String name) {
|
2017-08-23 04:48:42 +02:00
|
|
|
return name.length() <= NAME_MAX_LENGTH && PATTERN.matcher(name).matches();
|
2017-08-08 12:54:35 +02:00
|
|
|
}
|
|
|
|
|
2017-07-30 00:30:33 +02:00
|
|
|
private final Interface iface = new Interface();
|
2017-08-13 14:24:03 +02:00
|
|
|
private boolean isEnabled;
|
2017-08-16 11:26:45 +02:00
|
|
|
private boolean isPrimary;
|
2017-08-08 12:54:12 +02:00
|
|
|
private String name;
|
2017-07-30 00:30:33 +02:00
|
|
|
private final ObservableList<Peer> peers = new ObservableArrayList<>();
|
2017-07-29 13:08:54 +02:00
|
|
|
|
2017-08-20 01:50:35 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-08-16 08:06:05 +02:00
|
|
|
@Override
|
|
|
|
public int compareTo(@NonNull final Config config) {
|
|
|
|
return getName().compareTo(config.getName());
|
|
|
|
}
|
|
|
|
|
2017-08-13 14:24:03 +02:00
|
|
|
@Override
|
|
|
|
public Config copy() {
|
|
|
|
final Config copy = new Config();
|
|
|
|
copy.copyFrom(this);
|
|
|
|
return copy;
|
2017-08-01 04:14:42 +02:00
|
|
|
}
|
|
|
|
|
2017-08-13 14:24:03 +02:00
|
|
|
@Override
|
|
|
|
public void copyFrom(final Config source) {
|
2017-08-24 01:02:37 +02:00
|
|
|
if (source != null) {
|
|
|
|
iface.copyFrom(source.iface);
|
|
|
|
isEnabled = source.isEnabled;
|
|
|
|
isPrimary = source.isPrimary;
|
|
|
|
name = source.name;
|
|
|
|
peers.clear();
|
|
|
|
for (final Peer peer : source.peers)
|
|
|
|
addPeer(peer);
|
|
|
|
} else {
|
|
|
|
iface.copyFrom(null);
|
|
|
|
isEnabled = false;
|
|
|
|
isPrimary = false;
|
|
|
|
name = null;
|
|
|
|
peers.clear();
|
|
|
|
}
|
2017-08-01 04:14:42 +02:00
|
|
|
}
|
|
|
|
|
2017-07-30 00:30:33 +02:00
|
|
|
public Interface getInterface() {
|
|
|
|
return iface;
|
2017-07-29 13:08:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-08 12:54:12 +02:00
|
|
|
@Bindable
|
2017-07-29 13:08:54 +02:00
|
|
|
public String getName() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2017-07-30 00:30:33 +02:00
|
|
|
public ObservableList<Peer> getPeers() {
|
|
|
|
return peers;
|
|
|
|
}
|
|
|
|
|
2017-08-13 14:24:03 +02:00
|
|
|
@Bindable
|
|
|
|
public boolean isEnabled() {
|
|
|
|
return isEnabled;
|
|
|
|
}
|
|
|
|
|
2017-08-16 11:26:45 +02:00
|
|
|
@Bindable
|
|
|
|
public boolean isPrimary() {
|
|
|
|
return isPrimary;
|
|
|
|
}
|
|
|
|
|
2017-08-13 14:24:03 +02:00
|
|
|
public void parseFrom(final InputStream stream)
|
2017-07-30 00:30:33 +02:00
|
|
|
throws IOException {
|
2017-08-13 14:24:03 +02:00
|
|
|
peers.clear();
|
2017-07-30 00:30:33 +02:00
|
|
|
try (BufferedReader reader = new BufferedReader(
|
|
|
|
new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
|
|
|
Peer currentPeer = null;
|
|
|
|
String line;
|
|
|
|
while ((line = reader.readLine()) != null) {
|
2017-08-13 14:24:03 +02:00
|
|
|
if (line.isEmpty())
|
|
|
|
continue;
|
|
|
|
if ("[Interface]".equals(line)) {
|
2017-07-30 00:30:33 +02:00
|
|
|
currentPeer = null;
|
2017-08-13 14:24:03 +02:00
|
|
|
} else if ("[Peer]".equals(line)) {
|
2017-08-20 01:50:35 +02:00
|
|
|
currentPeer = addPeer();
|
2017-07-30 00:30:33 +02:00
|
|
|
} else if (currentPeer == null) {
|
|
|
|
iface.parseFrom(line);
|
|
|
|
} else {
|
|
|
|
currentPeer.parseFrom(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-29 13:08:54 +02:00
|
|
|
}
|
|
|
|
|
2017-08-16 07:57:27 +02:00
|
|
|
public void setIsEnabled(final boolean isEnabled) {
|
2017-08-13 14:24:03 +02:00
|
|
|
this.isEnabled = isEnabled;
|
|
|
|
notifyPropertyChanged(BR.enabled);
|
2017-08-01 04:13:01 +02:00
|
|
|
}
|
|
|
|
|
2017-08-16 11:26:45 +02:00
|
|
|
public void setIsPrimary(final boolean isPrimary) {
|
|
|
|
this.isPrimary = isPrimary;
|
|
|
|
notifyPropertyChanged(BR.primary);
|
|
|
|
}
|
|
|
|
|
2017-08-13 14:24:03 +02:00
|
|
|
public void setName(final String name) {
|
|
|
|
if (name != null && !name.isEmpty() && !isNameValid(name))
|
|
|
|
throw new IllegalArgumentException();
|
2017-08-08 12:54:12 +02:00
|
|
|
this.name = name;
|
|
|
|
notifyPropertyChanged(BR.name);
|
|
|
|
}
|
|
|
|
|
2017-07-29 13:08:54 +02:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2017-08-13 14:24:03 +02:00
|
|
|
final StringBuilder sb = new StringBuilder().append(iface);
|
|
|
|
for (final Peer peer : peers)
|
|
|
|
sb.append('\n').append(peer);
|
2017-07-30 00:30:33 +02:00
|
|
|
return sb.toString();
|
2017-07-29 13:08:54 +02:00
|
|
|
}
|
2017-08-17 10:32:01 +02:00
|
|
|
|
|
|
|
public String validate() {
|
|
|
|
if (name == null || !isNameValid(name))
|
|
|
|
return "This configuration does not have a valid name.";
|
|
|
|
if (iface.getPublicKey() == null)
|
|
|
|
return "This configuration does not have a valid keypair.";
|
|
|
|
return null;
|
|
|
|
}
|
2017-07-29 13:08:54 +02:00
|
|
|
}
|