aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app/src/main/java/com/wireguard/android/model
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/com/wireguard/android/model')
-rw-r--r--app/src/main/java/com/wireguard/android/model/ApplicationData.java54
-rw-r--r--app/src/main/java/com/wireguard/android/model/Tunnel.java158
-rw-r--r--app/src/main/java/com/wireguard/android/model/TunnelManager.java300
3 files changed, 0 insertions, 512 deletions
diff --git a/app/src/main/java/com/wireguard/android/model/ApplicationData.java b/app/src/main/java/com/wireguard/android/model/ApplicationData.java
deleted file mode 100644
index 65edff90..00000000
--- a/app/src/main/java/com/wireguard/android/model/ApplicationData.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package com.wireguard.android.model;
-
-import androidx.databinding.BaseObservable;
-import androidx.databinding.Bindable;
-import android.graphics.drawable.Drawable;
-
-import com.wireguard.android.BR;
-import com.wireguard.util.Keyed;
-
-public class ApplicationData extends BaseObservable implements Keyed<String> {
- private final Drawable icon;
- private final String name;
- private final String packageName;
- private boolean excludedFromTunnel;
-
- public ApplicationData(final Drawable icon, final String name, final String packageName, final boolean excludedFromTunnel) {
- this.icon = icon;
- this.name = name;
- this.packageName = packageName;
- this.excludedFromTunnel = excludedFromTunnel;
- }
-
- public Drawable getIcon() {
- return icon;
- }
-
- @Override
- public String getKey() {
- return name;
- }
-
- public String getName() {
- return name;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- @Bindable
- public boolean isExcludedFromTunnel() {
- return excludedFromTunnel;
- }
-
- public void setExcludedFromTunnel(final boolean excludedFromTunnel) {
- this.excludedFromTunnel = excludedFromTunnel;
- notifyPropertyChanged(BR.excludedFromTunnel);
- }
-}
diff --git a/app/src/main/java/com/wireguard/android/model/Tunnel.java b/app/src/main/java/com/wireguard/android/model/Tunnel.java
deleted file mode 100644
index 49e78a22..00000000
--- a/app/src/main/java/com/wireguard/android/model/Tunnel.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package com.wireguard.android.model;
-
-import androidx.databinding.BaseObservable;
-import androidx.databinding.Bindable;
-import androidx.annotation.Nullable;
-
-import com.wireguard.android.BR;
-import com.wireguard.android.util.ExceptionLoggers;
-import com.wireguard.config.Config;
-import com.wireguard.util.Keyed;
-
-import java.util.regex.Pattern;
-
-import java9.util.concurrent.CompletableFuture;
-import java9.util.concurrent.CompletionStage;
-
-/**
- * Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
- */
-
-public class Tunnel extends BaseObservable implements Keyed<String> {
- public static final int NAME_MAX_LENGTH = 15;
- private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,15}");
-
- private final TunnelManager manager;
- @Nullable private Config config;
- private String name;
- private State state;
- @Nullable private Statistics statistics;
-
- Tunnel(final TunnelManager manager, final String name,
- @Nullable final Config config, final State state) {
- this.manager = manager;
- this.name = name;
- this.config = config;
- this.state = state;
- }
-
- public static boolean isNameInvalid(final CharSequence name) {
- return !NAME_PATTERN.matcher(name).matches();
- }
-
- public CompletionStage<Void> delete() {
- return manager.delete(this);
- }
-
- @Bindable
- @Nullable
- public Config getConfig() {
- if (config == null)
- manager.getTunnelConfig(this).whenComplete(ExceptionLoggers.E);
- return config;
- }
-
- public CompletionStage<Config> getConfigAsync() {
- if (config == null)
- return manager.getTunnelConfig(this);
- return CompletableFuture.completedFuture(config);
- }
-
- @Override
- public String getKey() {
- return name;
- }
-
- @Bindable
- public String getName() {
- return name;
- }
-
- @Bindable
- public State getState() {
- return state;
- }
-
- public CompletionStage<State> getStateAsync() {
- return TunnelManager.getTunnelState(this);
- }
-
- @Bindable
- @Nullable
- public Statistics getStatistics() {
- // FIXME: Check age of statistics.
- if (statistics == null)
- TunnelManager.getTunnelStatistics(this).whenComplete(ExceptionLoggers.E);
- return statistics;
- }
-
- public CompletionStage<Statistics> getStatisticsAsync() {
- // FIXME: Check age of statistics.
- if (statistics == null)
- return TunnelManager.getTunnelStatistics(this);
- return CompletableFuture.completedFuture(statistics);
- }
-
- Config onConfigChanged(final Config config) {
- this.config = config;
- notifyPropertyChanged(BR.config);
- return config;
- }
-
- public String onNameChanged(final String name) {
- this.name = name;
- notifyPropertyChanged(BR.name);
- return name;
- }
-
- State onStateChanged(final State state) {
- if (state != State.UP)
- onStatisticsChanged(null);
- this.state = state;
- notifyPropertyChanged(BR.state);
- return state;
- }
-
- @Nullable
- Statistics onStatisticsChanged(@Nullable final Statistics statistics) {
- this.statistics = statistics;
- notifyPropertyChanged(BR.statistics);
- return statistics;
- }
-
- public CompletionStage<Config> setConfig(final Config config) {
- if (!config.equals(this.config))
- return manager.setTunnelConfig(this, config);
- return CompletableFuture.completedFuture(this.config);
- }
-
- public CompletionStage<String> setName(final String name) {
- if (!name.equals(this.name))
- return manager.setTunnelName(this, name);
- return CompletableFuture.completedFuture(this.name);
- }
-
- public CompletionStage<State> setState(final State state) {
- if (state != this.state)
- return manager.setTunnelState(this, state);
- return CompletableFuture.completedFuture(this.state);
- }
-
- public enum State {
- DOWN,
- TOGGLE,
- UP;
-
- public static State of(final boolean running) {
- return running ? UP : DOWN;
- }
- }
-
- public static class Statistics extends BaseObservable {
- }
-}
diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
deleted file mode 100644
index 2deea6df..00000000
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package com.wireguard.android.model;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import androidx.databinding.BaseObservable;
-import androidx.databinding.Bindable;
-import androidx.annotation.Nullable;
-
-import com.wireguard.android.Application;
-import com.wireguard.android.BR;
-import com.wireguard.android.R;
-import com.wireguard.android.configStore.ConfigStore;
-import com.wireguard.android.model.Tunnel.State;
-import com.wireguard.android.model.Tunnel.Statistics;
-import com.wireguard.android.util.ExceptionLoggers;
-import com.wireguard.android.util.ObservableSortedKeyedArrayList;
-import com.wireguard.android.util.ObservableSortedKeyedList;
-import com.wireguard.config.Config;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Set;
-
-import java9.util.Comparators;
-import java9.util.concurrent.CompletableFuture;
-import java9.util.concurrent.CompletionStage;
-import java9.util.stream.Collectors;
-import java9.util.stream.StreamSupport;
-
-/**
- * Maintains and mediates changes to the set of available WireGuard tunnels,
- */
-
-public final class TunnelManager extends BaseObservable {
- private static final Comparator<String> COMPARATOR = Comparators.<String>thenComparing(
- String.CASE_INSENSITIVE_ORDER, Comparators.naturalOrder());
- private static final String KEY_LAST_USED_TUNNEL = "last_used_tunnel";
- private static final String KEY_RESTORE_ON_BOOT = "restore_on_boot";
- private static final String KEY_RUNNING_TUNNELS = "enabled_configs";
-
- private final CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>();
- private final ConfigStore configStore;
- private final Context context = Application.get();
- private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>();
- private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
- private boolean haveLoaded;
- @Nullable private Tunnel lastUsedTunnel;
-
- public TunnelManager(final ConfigStore configStore) {
- this.configStore = configStore;
- }
-
- static CompletionStage<State> getTunnelState(final Tunnel tunnel) {
- return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getState(tunnel))
- .thenApply(tunnel::onStateChanged);
- }
-
- static CompletionStage<Statistics> getTunnelStatistics(final Tunnel tunnel) {
- return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getStatistics(tunnel))
- .thenApply(tunnel::onStatisticsChanged);
- }
-
- private Tunnel addToList(final String name, @Nullable final Config config, final State state) {
- final Tunnel tunnel = new Tunnel(this, name, config, state);
- tunnels.add(tunnel);
- return tunnel;
- }
-
- public CompletionStage<Tunnel> create(final String name, @Nullable final Config config) {
- if (Tunnel.isNameInvalid(name))
- return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
- if (tunnels.containsKey(name)) {
- final String message = context.getString(R.string.tunnel_error_already_exists, name);
- return CompletableFuture.failedFuture(new IllegalArgumentException(message));
- }
- return Application.getAsyncWorker().supplyAsync(() -> configStore.create(name, config))
- .thenApply(savedConfig -> addToList(name, savedConfig, State.DOWN));
- }
-
- CompletionStage<Void> delete(final Tunnel tunnel) {
- final State originalState = tunnel.getState();
- final boolean wasLastUsed = tunnel == lastUsedTunnel;
- // Make sure nothing touches the tunnel.
- if (wasLastUsed)
- setLastUsedTunnel(null);
- tunnels.remove(tunnel);
- return Application.getAsyncWorker().runAsync(() -> {
- if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.DOWN);
- try {
- configStore.delete(tunnel.getName());
- } catch (final Exception e) {
- if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.UP);
- // Re-throw the exception to fail the completion.
- throw e;
- }
- }).whenComplete((x, e) -> {
- if (e == null)
- return;
- // Failure, put the tunnel back.
- tunnels.add(tunnel);
- if (wasLastUsed)
- setLastUsedTunnel(tunnel);
- });
- }
-
- @Bindable
- @Nullable
- public Tunnel getLastUsedTunnel() {
- return lastUsedTunnel;
- }
-
- CompletionStage<Config> getTunnelConfig(final Tunnel tunnel) {
- return Application.getAsyncWorker().supplyAsync(() -> configStore.load(tunnel.getName()))
- .thenApply(tunnel::onConfigChanged);
- }
-
- public CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> getTunnels() {
- return completableTunnels;
- }
-
- public void onCreate() {
- Application.getAsyncWorker().supplyAsync(configStore::enumerate)
- .thenAcceptBoth(Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().enumerate()), this::onTunnelsLoaded)
- .whenComplete(ExceptionLoggers.E);
- }
-
- @SuppressWarnings("unchecked")
- private void onTunnelsLoaded(final Iterable<String> present, final Collection<String> running) {
- for (final String name : present)
- addToList(name, null, running.contains(name) ? State.UP : State.DOWN);
- final String lastUsedName = Application.getSharedPreferences().getString(KEY_LAST_USED_TUNNEL, null);
- if (lastUsedName != null)
- setLastUsedTunnel(tunnels.get(lastUsedName));
- final CompletableFuture<Void>[] toComplete;
- synchronized (delayedLoadRestoreTunnels) {
- haveLoaded = true;
- toComplete = delayedLoadRestoreTunnels.toArray(new CompletableFuture[delayedLoadRestoreTunnels.size()]);
- delayedLoadRestoreTunnels.clear();
- }
- restoreState(true).whenComplete((v, t) -> {
- for (final CompletableFuture<Void> f : toComplete) {
- if (t == null)
- f.complete(v);
- else
- f.completeExceptionally(t);
- }
- });
-
- completableTunnels.complete(tunnels);
- }
-
- public void refreshTunnelStates() {
- Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().enumerate())
- .thenAccept(running -> {
- for (final Tunnel tunnel : tunnels)
- tunnel.onStateChanged(running.contains(tunnel.getName()) ? State.UP : State.DOWN);
- })
- .whenComplete(ExceptionLoggers.E);
- }
-
- public CompletionStage<Void> restoreState(final boolean force) {
- if (!force && !Application.getSharedPreferences().getBoolean(KEY_RESTORE_ON_BOOT, false))
- return CompletableFuture.completedFuture(null);
- synchronized (delayedLoadRestoreTunnels) {
- if (!haveLoaded) {
- final CompletableFuture<Void> f = new CompletableFuture<>();
- delayedLoadRestoreTunnels.add(f);
- return f;
- }
- }
- final Set<String> previouslyRunning = Application.getSharedPreferences().getStringSet(KEY_RUNNING_TUNNELS, null);
- if (previouslyRunning == null)
- return CompletableFuture.completedFuture(null);
- return CompletableFuture.allOf(StreamSupport.stream(tunnels)
- .filter(tunnel -> previouslyRunning.contains(tunnel.getName()))
- .map(tunnel -> setTunnelState(tunnel, State.UP))
- .toArray(CompletableFuture[]::new));
- }
-
- public void saveState() {
- final Set<String> runningTunnels = StreamSupport.stream(tunnels)
- .filter(tunnel -> tunnel.getState() == State.UP)
- .map(Tunnel::getName)
- .collect(Collectors.toUnmodifiableSet());
- Application.getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply();
- }
-
- private void setLastUsedTunnel(@Nullable final Tunnel tunnel) {
- if (tunnel == lastUsedTunnel)
- return;
- lastUsedTunnel = tunnel;
- notifyPropertyChanged(BR.lastUsedTunnel);
- if (tunnel != null)
- Application.getSharedPreferences().edit().putString(KEY_LAST_USED_TUNNEL, tunnel.getName()).apply();
- else
- Application.getSharedPreferences().edit().remove(KEY_LAST_USED_TUNNEL).apply();
- }
-
- CompletionStage<Config> setTunnelConfig(final Tunnel tunnel, final Config config) {
- return Application.getAsyncWorker().supplyAsync(() -> {
- final Config appliedConfig = Application.getBackend().applyConfig(tunnel, config);
- return configStore.save(tunnel.getName(), appliedConfig);
- }).thenApply(tunnel::onConfigChanged);
- }
-
- CompletionStage<String> setTunnelName(final Tunnel tunnel, final String name) {
- if (Tunnel.isNameInvalid(name))
- return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
- if (tunnels.containsKey(name)) {
- final String message = context.getString(R.string.tunnel_error_already_exists, name);
- return CompletableFuture.failedFuture(new IllegalArgumentException(message));
- }
- final State originalState = tunnel.getState();
- final boolean wasLastUsed = tunnel == lastUsedTunnel;
- // Make sure nothing touches the tunnel.
- if (wasLastUsed)
- setLastUsedTunnel(null);
- tunnels.remove(tunnel);
- return Application.getAsyncWorker().supplyAsync(() -> {
- if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.DOWN);
- configStore.rename(tunnel.getName(), name);
- final String newName = tunnel.onNameChanged(name);
- if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.UP);
- return newName;
- }).whenComplete((newName, e) -> {
- // On failure, we don't know what state the tunnel might be in. Fix that.
- if (e != null)
- getTunnelState(tunnel);
- // Add the tunnel back to the manager, under whatever name it thinks it has.
- tunnels.add(tunnel);
- if (wasLastUsed)
- setLastUsedTunnel(tunnel);
- });
- }
-
- CompletionStage<State> setTunnelState(final Tunnel tunnel, final State state) {
- // Ensure the configuration is loaded before trying to use it.
- return tunnel.getConfigAsync().thenCompose(x ->
- Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().setState(tunnel, state))
- ).whenComplete((newState, e) -> {
- // Ensure onStateChanged is always called (failure or not), and with the correct state.
- tunnel.onStateChanged(e == null ? newState : tunnel.getState());
- if (e == null && newState == State.UP)
- setLastUsedTunnel(tunnel);
- saveState();
- });
- }
-
- public static final class IntentReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(final Context context, @Nullable final Intent intent) {
- final TunnelManager manager = Application.getTunnelManager();
- if (intent == null)
- return;
- final String action = intent.getAction();
- if (action == null)
- return;
-
- if ("com.wireguard.android.action.REFRESH_TUNNEL_STATES".equals(action)) {
- manager.refreshTunnelStates();
- return;
- }
-
- /* We disable the below, for now, as the security model of allowing this
- * might take a bit more consideration.
- */
- if (true)
- return;
-
- final State state;
- if ("com.wireguard.android.action.SET_TUNNEL_UP".equals(action))
- state = State.UP;
- else if ("com.wireguard.android.action.SET_TUNNEL_DOWN".equals(action))
- state = State.DOWN;
- else
- return;
-
- final String tunnelName = intent.getStringExtra("tunnel");
- if (tunnelName == null)
- return;
- manager.getTunnels().thenAccept(tunnels -> {
- final Tunnel tunnel = tunnels.get(tunnelName);
- if (tunnel == null)
- return;
- manager.setTunnelState(tunnel, state);
- });
- }
- }
-}