diff options
author | Parménides GV <parmegv@sdf.org> | 2015-06-16 11:28:05 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2015-06-16 11:28:05 +0200 |
commit | 66c79953db6876ec17a7ebf50dc4fd07d24fae37 (patch) | |
tree | 67075abe6ea28f7fc7213f654b86464b13507058 /app/src/main/java | |
parent | 1f41fec6765e49838141ad29151713c7ac3dd17c (diff) | |
parent | e533cf6939e3ea4233aa8a82812f8ce5fcb565ca (diff) |
Merge branch 'develop'0.9.4
Diffstat (limited to 'app/src/main/java')
38 files changed, 1300 insertions, 1023 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java index 0eb1d99c..90216a70 100644 --- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java +++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java @@ -7,8 +7,6 @@ package de.blinkt.openvpn; import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.R; - import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; @@ -117,26 +115,29 @@ public class LaunchVPN extends Activity { } } - + @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode==START_VPN_PROFILE) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean showlogwindow = prefs.getBoolean("showlogwindow", true); - - if(!mhideLog && showlogwindow) - showLogWindow(); - new startOpenVpnThread().start(); - } else if (resultCode == Activity.RESULT_CANCELED) { - // User does not want us to start, so we just vanish - VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled, ConnectionStatus.LEVEL_NOTCONNECTED); - - finish(); + if(resultCode == Activity.RESULT_OK) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + boolean showLogWindow = prefs.getBoolean("showlogwindow", true); + + if(!mhideLog && showLogWindow) + showLogWindow(); + new startOpenVpnThread().start(); + } else if (resultCode == Activity.RESULT_CANCELED) { + // User does not want us to start, so we just vanish + VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled, + ConnectionStatus.LEVEL_NOTCONNECTED); + + finish(); + } } } - + void showLogWindow() { Intent startLW = new Intent(getBaseContext(),LogWindow.class); diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index 4f747d21..43e1b57c 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -7,8 +7,6 @@ package de.blinkt.openvpn; import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.R; - import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; @@ -98,7 +96,7 @@ public class VpnProfile implements Serializable, Cloneable { // variable named wrong and should haven beeen transient // but needs to keep wrong name to guarante loading of old // profiles - public transient boolean profileDleted = false; + public transient boolean profileDeleted = false; public int mAuthenticationType = TYPE_KEYSTORE; public String mName; public String mAlias; @@ -156,7 +154,7 @@ public class VpnProfile implements Serializable, Cloneable { public boolean mRemoteRandom=false; public HashSet<String> mAllowedAppsVpn = new HashSet<String>(); public boolean mAllowedAppsVpnAreDisallowed = true; - + public String mProfileCreator; /* Options no long used in new profiles */ public String mServerName = "openvpn.blinkt.de"; @@ -699,7 +697,11 @@ public class VpnProfile implements Serializable, Cloneable { protected VpnProfile clone() throws CloneNotSupportedException { VpnProfile copy = (VpnProfile) super.clone(); copy.mUuid = UUID.randomUUID(); - copy.mConnections = mConnections.clone(); + copy.mConnections = new Connection[mConnections.length]; + int i=0; + for (Connection conn: mConnections) { + copy.mConnections[i++]=conn.clone(); + } copy.mAllowedAppsVpn = (HashSet<String>) mAllowedAppsVpn.clone(); return copy; } diff --git a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java index e525abd5..94ed8a0b 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java +++ b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java @@ -54,6 +54,7 @@ class CIDRIP { } else { return false; } + } static long getInt(String ipaddr) { diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java index 5f5d486c..232c454b 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java @@ -31,6 +31,9 @@ public class ConfigParser { public static final String CONVERTED_PROFILE = "converted Profile"; private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>(); private HashMap<String, Vector<String>> meta = new HashMap<String, Vector<String>>(); + private String auth_user_pass_file; + private String crl_verify_file; + public void parseConfig(Reader reader) throws IOException, ConfigParseError { @@ -114,6 +117,14 @@ public class ConfigParser { } + public String getAuthUserPassFile() { + return auth_user_pass_file; + } + + public String getCrlVerifyFile() { + return crl_verify_file; + } + enum linestate { initial, readin_single_quote, reading_quoted, reading_unquoted, done @@ -572,6 +583,7 @@ public class ConfigParser { options.put("remotetls", remotetls); Vector<String> authuser = getOption("auth-user-pass", 0, 1); + if (authuser != null) { if (noauthtypeset) { np.mAuthenticationType = VpnProfile.TYPE_USERPASS; @@ -581,12 +593,24 @@ public class ConfigParser { np.mAuthenticationType = VpnProfile.TYPE_USERPASS_KEYSTORE; } if (authuser.size() > 1) { - // Set option value to password get to embed later. + if (!authuser.get(1).startsWith(VpnProfile.INLINE_TAG)) + auth_user_pass_file = authuser.get(1); np.mUsername = null; useEmbbedUserAuth(np, authuser.get(1)); } } + Vector<String> crlfile = getOption("crl-verify", 1, 2); + if (crlfile != null) { + // If the 'dir' parameter is present just add it as custom option .. + np.mCustomConfigOptions += TextUtils.join(" ", crlfile) + "\n"; + if (crlfile.size() == 2) { + // Save the filename for the config converter to add later + crl_verify_file = crlfile.get(1); + } + } + + Pair<Connection, Connection[]> conns = parseConnectionOptions(null); np.mConnections = conns.second; @@ -761,6 +785,16 @@ public class ConfigParser { } } + public static void removeCRLCustomOption(VpnProfile np) { + String lines[] = np.mCustomConfigOptions.split("\\r?\\n"); + Vector<String> keeplines = new Vector<>(); + for (String l : lines) { + if (!l.startsWith("crl-verify ")) + keeplines.add(l); + } + np.mCustomConfigOptions = TextUtils.join("\n", keeplines); + } + private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError { for (String option : unsupportedOptions) if (options.containsKey(option)) @@ -772,7 +806,8 @@ public class ConfigParser { if (options.size() > 0) { - np.mCustomConfigOptions += "# These Options were found in the config file do not map to config settings:\n"; + np.mCustomConfigOptions = "# These options found in the config file do not map to config settings:\n" + + np.mCustomConfigOptions; for (Vector<Vector<String>> option : options.values()) { diff --git a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java index 56a574dc..6e9e63c5 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java @@ -38,5 +38,4 @@ public class ICSOpenVPNApplication extends Application { //ACRA.init(this); } } - } diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 3c1ec064..f9cb9a86 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -16,7 +16,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.NetworkRequest; import android.net.VpnService; import android.os.Binder; import android.os.Build; @@ -51,8 +50,6 @@ import static de.blinkt.openvpn.core.NetworkSpace.ipAddress; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NONETWORK; import se.leap.bitmaskclient.Dashboard; @@ -65,7 +62,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private static final String RESUME_VPN = "se.leap.bitmaskclient.RESUME_VPN"; private static final int OPENVPN_STATUS = 1; private static boolean mNotificationAlwaysVisible = false; - private final Vector<String> mDnslist = new Vector<String>(); + private final Vector<String> mDnslist = new Vector<>(); private final NetworkSpace mRoutes = new NetworkSpace(); private final NetworkSpace mRoutesv6 = new NetworkSpace(); private final IBinder mBinder = new LocalBinder(); @@ -84,7 +81,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private String mLastTunCfg; private String mRemoteGW; private final Object mProcessLock = new Object(); - private LollipopDeviceStateListener mLollipopDeviceStateListener; // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java public static String humanReadableByteCount(long bytes, boolean mbit) { @@ -238,13 +234,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac //ignore exception - } catch (NoSuchMethodException nsm) { - VpnStatus.logException(nsm); - } catch (IllegalArgumentException e) { - VpnStatus.logException(e); - } catch (IllegalAccessException e) { - VpnStatus.logException(e); - } catch (InvocationTargetException e) { + } catch (NoSuchMethodException | IllegalArgumentException | + InvocationTargetException | IllegalAccessException e) { VpnStatus.logException(e); } @@ -328,6 +319,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac /* The intent is null when the service has been restarted */ if (intent == null) { mProfile = ProfileManager.getLastConnectedProfile(this, false); + VpnStatus.logInfo(R.string.service_restarted); /* Got no profile, just stop */ if (mProfile == null) { @@ -415,7 +407,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } else { - HashMap<String, String> env = new HashMap<String, String>(); + HashMap<String, String> env = new HashMap<>(); processThread = new OpenVPNThread(this, argv, env, nativeLibraryDirectory); } @@ -431,7 +423,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac ProfileManager.setConnectedVpnProfile(this, mProfile); /* TODO: At the moment we have no way to handle asynchronous PW input - * Fixing will also allow to handle challenge/responsee authentication */ + * Fixing will also allow to handle challenge/response authentication */ if (mProfile.needUserPWInput(true) != 0) return START_NOT_STICKY; @@ -442,17 +434,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac try { Class cl = Class.forName("de.blinkt.openvpn.core.OpenVPNThreadv3"); return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class, VpnProfile.class).newInstance(this, mProfile); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { + } catch (IllegalArgumentException | InstantiationException | InvocationTargetException | + NoSuchMethodException | ClassNotFoundException | IllegalAccessException e ) { e.printStackTrace(); } return null; @@ -501,8 +484,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.logInfo(R.string.last_openvpn_tun_config); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN) - { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN) { allowAllAFFamilies(builder); } @@ -576,6 +558,26 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } + if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mDnslist.size() >= 1) { + // Check if the first DNS Server is in the VPN range + try { + ipAddress dnsServer = new ipAddress(new CIDRIP(mDnslist.get(0), 32), true); + boolean dnsIncluded=false; + for (ipAddress net : positiveIPv4Routes) { + if (net.containsNet(dnsServer)) { + dnsIncluded = true; + } + } + if (!dnsIncluded) { + String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS add a custom route to your DNS Server (%s) or change to a DNS inside your VPN range", mDnslist.get(0)); + VpnStatus.logWarning(samsungwarning); + } + } catch (Exception e) { + VpnStatus.logError("Error parsing DNS Server IP: " + mDnslist.get(0)); + } + } + + if (mDomain != null) builder.addSearchDomain(mDomain); @@ -616,7 +618,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac try { //Debug.stopMethodTracing(); ParcelFileDescriptor tun = builder.establish(); - if (tun==null) + if (tun == null) throw new NullPointerException("Android establish() method returned null (Really broken network configuration?)"); return tun; } catch (Exception e) { @@ -636,22 +638,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac builder.allowFamily(OsConstants.AF_INET6); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - void removeLollipopCMListener() { - ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE); - cm.unregisterNetworkCallback(mLollipopDeviceStateListener); - mLollipopDeviceStateListener = null; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - void addLollipopCMListener() { - ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE); - NetworkRequest.Builder nrb = new NetworkRequest.Builder(); - - mLollipopDeviceStateListener = new LollipopDeviceStateListener(); - cm.registerNetworkCallback(nrb.build(), mLollipopDeviceStateListener); - } - private void addLocalNetworksToRoutes() { // Add local network interfaces @@ -667,11 +653,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac intf.startsWith("tun") || intf.startsWith("rmnet")) continue; - if (ipAddr==null || netMask == null) { + if (ipAddr == null || netMask == null) { VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes)); continue; } - + if (ipAddr.equals(mLocalIP.mIp)) continue; @@ -854,21 +840,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mDisplayBytecount = true; mConnecttime = System.currentTimeMillis(); lowpriority = true; - if(mProfile.mPersistTun) { - NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - ns.cancel(OPENVPN_STATUS); - return; - } - } else if (level == LEVEL_NONETWORK || level == LEVEL_NOTCONNECTED) { - NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - ns.cancel(OPENVPN_STATUS); - return; - } else if (level != LEVEL_NOTCONNECTED && mConnecttime > 0) { - mDisplayBytecount = false; - String msg = "Traffic is blocked until the VPN becomes active."; - String ticker = msg; - showNotification(msg, ticker, lowpriority , 0, level); - return; + String ns = Context.NOTIFICATION_SERVICE; + NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); + mNotificationManager.cancel(OPENVPN_STATUS); } else { mDisplayBytecount = false; } @@ -878,8 +852,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // CONNECTED // Does not work :( String msg = getString(resid); - String ticker = msg; - showNotification(msg + " " + logmessage, ticker, lowpriority, 0, level); + // showNotification(msg + " " + logmessage, msg, lowpriority, 0, level); } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java index 1ebc0a57..086cdb44 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java @@ -5,11 +5,15 @@ package de.blinkt.openvpn.core; -import java.io.FileNotFoundException; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.preference.PreferenceManager; + import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.io.StreamCorruptedException; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -17,213 +21,173 @@ import java.util.Set; import de.blinkt.openvpn.VpnProfile; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.preference.PreferenceManager; - public class ProfileManager { - private static final String PREFS_NAME = "VPNList"; + private static final String PREFS_NAME = "VPNList"; + private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile"; + private static ProfileManager instance; + private static VpnProfile mLastConnectedVpn = null; + private HashMap<String, VpnProfile> profiles = new HashMap<>(); + private static VpnProfile tmpprofile = null; - private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile"; + private static VpnProfile get(String key) { + if (tmpprofile != null && tmpprofile.getUUIDString().equals(key)) + return tmpprofile; + if (instance == null) + return null; + return instance.profiles.get(key); + + } - private static ProfileManager instance; + private ProfileManager() { + } + private static void checkInstance(Context context) { + if (instance == null) { + instance = new ProfileManager(); + instance.loadVPNList(context); + } + } - private static VpnProfile mLastConnectedVpn=null; - private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>(); - private static VpnProfile tmpprofile=null; + synchronized public static ProfileManager getInstance(Context context) { + checkInstance(context); + return instance; + } + public static void setConntectedVpnProfileDisconnected(Context c) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); + Editor prefsedit = prefs.edit(); + prefsedit.putString(LAST_CONNECTED_PROFILE, null); + prefsedit.apply(); - private static VpnProfile get(String key) { - if (tmpprofile!=null && tmpprofile.getUUIDString().equals(key)) - return tmpprofile; - - if(instance==null) - return null; - return instance.profiles.get(key); - - } + } + public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); + Editor prefsedit = prefs.edit(); - - private ProfileManager() { } - - private static void checkInstance(Context context) { - if(instance == null) { - instance = new ProfileManager(); - instance.loadVPNList(context); - } - } + prefsedit.putString(LAST_CONNECTED_PROFILE, connectedrofile.getUUIDString()); + prefsedit.apply(); + mLastConnectedVpn = connectedrofile; - synchronized public static ProfileManager getInstance(Context context) { - checkInstance(context); - return instance; - } - - public static void setConntectedVpnProfileDisconnected(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - prefsedit.putString(LAST_CONNECTED_PROFILE, null); - prefsedit.apply(); - - } + } - public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - - prefsedit.putString(LAST_CONNECTED_PROFILE, connectedrofile.getUUIDString()); - prefsedit.apply(); - mLastConnectedVpn=connectedrofile; - - } - - public static VpnProfile getLastConnectedProfile(Context c, boolean onBoot) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); + public static VpnProfile getLastConnectedProfile(Context c, boolean onBoot) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); + boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); if (onBoot && !useStartOnBoot) return null; - - String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null); - if(lastConnectedProfile!=null) - return get(c, lastConnectedProfile); - else - return null; - } - - - - - public Collection<VpnProfile> getProfiles() { - return profiles.values(); - } - - public VpnProfile getProfileByName(String name) { - for (VpnProfile vpnp : profiles.values()) { - if(vpnp.getName().equals(name)) { - return vpnp; - } - } - return null; - } - - public void saveProfileList(Context context) { - SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Editor editor = sharedprefs.edit(); - editor.putStringSet("vpnlist", profiles.keySet()); - - // For reasing I do not understand at all - // Android saves my prefs file only one time - // if I remove the debug code below :( - int counter = sharedprefs.getInt("counter", 0); - editor.putInt("counter", counter+1); - editor.apply(); - - } - - public void addProfile(VpnProfile profile) { - profiles.put(profile.getUUID().toString(),profile); - - } - - public static void setTemporaryProfile(VpnProfile tmp) { - ProfileManager.tmpprofile = tmp; - } - - - public void saveProfile(Context context,VpnProfile profile) { - // First let basic settings save its state - - ObjectOutputStream vpnfile; - try { - vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE)); - - vpnfile.writeObject(profile); - vpnfile.flush(); - vpnfile.close(); - } catch (FileNotFoundException e) { - VpnStatus.logException("saving VPN profile", e); - throw new RuntimeException(e); - } catch (IOException e) { - VpnStatus.logException("saving VPN profile", e); - throw new RuntimeException(e); - } - } - - - private void loadVPNList(Context context) { - profiles = new HashMap<String, VpnProfile>(); - SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Set<String> vlist = listpref.getStringSet("vpnlist", null); - Exception exp =null; - if(vlist==null){ - vlist = new HashSet<String>(); - } - - for (String vpnentry : vlist) { - try { - ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp")); - VpnProfile vp = ((VpnProfile) vpnfile.readObject()); - - // Sanity check - if(vp==null || vp.mName==null || vp.getUUID()==null) - continue; + String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null); + if (lastConnectedProfile != null) + return get(c, lastConnectedProfile); + else + return null; + } - vp.upgradeProfile(); - profiles.put(vp.getUUID().toString(), vp); - } catch (StreamCorruptedException e) { - exp=e; - } catch (FileNotFoundException e) { - exp=e; - } catch (IOException e) { - exp=e; - } catch (ClassNotFoundException e) { - exp=e; - } - if(exp!=null) { - VpnStatus.logException("Loading VPN List",exp); - } - } - } + public Collection<VpnProfile> getProfiles() { + return profiles.values(); + } + + public VpnProfile getProfileByName(String name) { + for (VpnProfile vpnp : profiles.values()) { + if (vpnp.getName().equals(name)) { + return vpnp; + } + } + return null; + } + + public void saveProfileList(Context context) { + SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE); + Editor editor = sharedprefs.edit(); + editor.putStringSet("vpnlist", profiles.keySet()); + + // For reasing I do not understand at all + // Android saves my prefs file only one time + // if I remove the debug code below :( + int counter = sharedprefs.getInt("counter", 0); + editor.putInt("counter", counter + 1); + editor.apply(); + + } + + public void addProfile(VpnProfile profile) { + profiles.put(profile.getUUID().toString(), profile); + + } - public int getNumberOfProfiles() { - return profiles.size(); - } + public static void setTemporaryProfile(VpnProfile tmp) { + ProfileManager.tmpprofile = tmp; + } + public void saveProfile(Context context, VpnProfile profile) { + ObjectOutputStream vpnfile; + try { + vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"), Activity.MODE_PRIVATE)); - public void removeProfile(Context context,VpnProfile profile) { - String vpnentry = profile.getUUID().toString(); - profiles.remove(vpnentry); - saveProfileList(context); - context.deleteFile(vpnentry + ".vp"); - if(mLastConnectedVpn==profile) - mLastConnectedVpn=null; - - } + vpnfile.writeObject(profile); + vpnfile.flush(); + vpnfile.close(); + } catch (IOException e) { + VpnStatus.logException("saving VPN profile", e); + throw new RuntimeException(e); + } + } + + + private void loadVPNList(Context context) { + profiles = new HashMap<>(); + SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE); + Set<String> vlist = listpref.getStringSet("vpnlist", null); + if (vlist == null) { + vlist = new HashSet<>(); + } + + for (String vpnentry : vlist) { + try { + ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp")); + VpnProfile vp = ((VpnProfile) vpnfile.readObject()); + + // Sanity check + if (vp == null || vp.mName == null || vp.getUUID() == null) + continue; + + vp.upgradeProfile(); + profiles.put(vp.getUUID().toString(), vp); + } catch (IOException | ClassNotFoundException e) { + VpnStatus.logException("Loading VPN List", e); + } + } + } - public static VpnProfile get(Context context, String profileUUID) { - checkInstance(context); - return get(profileUUID); - } + public void removeProfile(Context context, VpnProfile profile) { + String vpnentry = profile.getUUID().toString(); + profiles.remove(vpnentry); + saveProfileList(context); + context.deleteFile(vpnentry + ".vp"); + if (mLastConnectedVpn == profile) + mLastConnectedVpn = null; + } + public static VpnProfile get(Context context, String profileUUID) { + checkInstance(context); + return get(profileUUID); + } - public static VpnProfile getLastConnectedVpn() { - return mLastConnectedVpn; - } + public static VpnProfile getLastConnectedVpn() { + return mLastConnectedVpn; + } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java index 73ed05bc..47cb633c 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java @@ -8,7 +8,6 @@ package de.blinkt.openvpn.core; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.os.Build; import java.io.File; @@ -67,14 +66,14 @@ public class VPNLaunchHelper { public static String[] buildOpenvpnArgv(Context c) { - Vector<String> args = new Vector<String>(); + Vector<String> args = new Vector<>(); // Add fixed paramenters //args.add("/data/data/de.blinkt.openvpn/lib/openvpn"); args.add(writeMiniVPN(c)); args.add("--config"); - args.add(c.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); + args.add(getConfigFilePath(c)); return args.toArray(new String[args.size()]); } diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java index ffc8097d..62a60643 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java @@ -6,6 +6,7 @@ package de.blinkt.openvpn.core; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -14,10 +15,10 @@ import android.content.pm.Signature; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import se.leap.bitmaskclient.R; +import android.text.TextUtils; import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; +import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.security.MessageDigest; @@ -32,28 +33,30 @@ import java.util.Locale; import java.util.UnknownFormatConversionException; import java.util.Vector; +import se.leap.bitmaskclient.R; + public class VpnStatus { - public static LinkedList<LogItem> logbuffer; + public static LinkedList<LogItem> logbuffer; - private static Vector<LogListener> logListener; - private static Vector<StateListener> stateListener; - private static Vector<ByteCountListener> byteCountListener; + private static Vector<LogListener> logListener; + private static Vector<StateListener> stateListener; + private static Vector<ByteCountListener> byteCountListener; - private static String mLaststatemsg=""; + private static String mLaststatemsg = ""; - private static String mLaststate = "NOPROCESS"; + private static String mLaststate = "NOPROCESS"; - private static int mLastStateresid=R.string.state_noprocess; + private static int mLastStateresid = R.string.state_noprocess; - private static long mlastByteCount[]={0,0,0,0}; + private static long mlastByteCount[] = {0, 0, 0, 0}; - public static void logException(LogLevel ll, String context, Exception e) { + public static void logException(LogLevel ll, String context, Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); LogItem li; - if (context !=null) { + if (context != null) { li = new LogItem(ll, R.string.unhandled_exception_context, e.getMessage(), sw.toString(), context); } else { li = new LogItem(ll, R.string.unhandled_exception, e.getMessage(), sw.toString()); @@ -71,18 +74,16 @@ public class VpnStatus { private static final int MAXLOGENTRIES = 1000; - public static final String MANAGMENT_PREFIX = "M:"; - public enum ConnectionStatus { LEVEL_CONNECTED, LEVEL_VPNPAUSED, LEVEL_CONNECTING_SERVER_REPLIED, LEVEL_CONNECTING_NO_SERVER_REPLY_YET, LEVEL_NONETWORK, - LEVEL_NOTCONNECTED, - LEVEL_AUTH_FAILED, - LEVEL_WAITING_FOR_USER_INPUT, - UNKNOWN_LEVEL + LEVEL_NOTCONNECTED, + LEVEL_AUTH_FAILED, + LEVEL_WAITING_FOR_USER_INPUT, + UNKNOWN_LEVEL } public enum LogLevel { @@ -93,6 +94,7 @@ public class VpnStatus { DEBUG(4); protected int mValue; + LogLevel(int value) { mValue = value; } @@ -103,59 +105,64 @@ public class VpnStatus { public static LogLevel getEnumByValue(int value) { switch (value) { - case 1: return INFO; - case 2: return ERROR; - case 3: return WARNING; - case 4: return DEBUG; - default: return null; + case 1: + return INFO; + case 2: + return ERROR; + case 3: + return WARNING; + case 4: + return DEBUG; + default: + return null; } } } // keytool -printcert -jarfile de.blinkt.openvpn_85.apk - public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109}; - public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43}; - public static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57}; + public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109}; + public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43}; + public static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57}; public static final byte[] fdroidkey = {-92, 111, -42, -46, 123, -96, -60, 79, -27, -31, 49, 103, 11, -54, -68, -27, 17, 2, 121, 104}; - private static ConnectionStatus mLastLevel=ConnectionStatus.LEVEL_NOTCONNECTED; + private static ConnectionStatus mLastLevel = ConnectionStatus.LEVEL_NOTCONNECTED; - static { - logbuffer = new LinkedList<LogItem>(); - logListener = new Vector<VpnStatus.LogListener>(); - stateListener = new Vector<VpnStatus.StateListener>(); - byteCountListener = new Vector<VpnStatus.ByteCountListener>(); - logInformation(); - } + static { + logbuffer = new LinkedList<>(); + logListener = new Vector<>(); + stateListener = new Vector<>(); + byteCountListener = new Vector<>(); + logInformation(); + } - public static class LogItem implements Parcelable { + public static class LogItem implements Parcelable { - private Object [] mArgs = null; - private String mMessage = null; - private int mRessourceId; - // Default log priority - LogLevel mLevel = LogLevel.INFO; - private long logtime = System.currentTimeMillis(); + private Object[] mArgs = null; + private String mMessage = null; + private int mRessourceId; + // Default log priority + LogLevel mLevel = LogLevel.INFO; + private long logtime = System.currentTimeMillis(); private int mVerbosityLevel = -1; - private LogItem(int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - } + private LogItem(int ressourceId, Object[] args) { + mRessourceId = ressourceId; + mArgs = args; + } public LogItem(LogLevel level, int verblevel, String message) { - mMessage=message; + mMessage = message; mLevel = level; mVerbosityLevel = verblevel; } @Override - public int describeContents() { - return 0; - } + public int describeContents() { + return 0; + } @Override @@ -169,65 +176,65 @@ public class VpnStatus { dest.writeLong(logtime); } - public LogItem(Parcel in) { - mArgs = in.readArray(Object.class.getClassLoader()); - mMessage = in.readString(); - mRessourceId = in.readInt(); - mLevel = LogLevel.getEnumByValue(in.readInt()); + public LogItem(Parcel in) { + mArgs = in.readArray(Object.class.getClassLoader()); + mMessage = in.readString(); + mRessourceId = in.readInt(); + mLevel = LogLevel.getEnumByValue(in.readInt()); mVerbosityLevel = in.readInt(); - logtime = in.readLong(); - } + logtime = in.readLong(); + } - public static final Parcelable.Creator<LogItem> CREATOR - = new Parcelable.Creator<LogItem>() { - public LogItem createFromParcel(Parcel in) { - return new LogItem(in); - } + public static final Parcelable.Creator<LogItem> CREATOR + = new Parcelable.Creator<LogItem>() { + public LogItem createFromParcel(Parcel in) { + return new LogItem(in); + } - public LogItem[] newArray(int size) { - return new LogItem[size]; - } - }; + public LogItem[] newArray(int size) { + return new LogItem[size]; + } + }; - public LogItem(LogLevel loglevel,int ressourceId, Object... args) { + public LogItem(LogLevel loglevel, int ressourceId, Object... args) { mRessourceId = ressourceId; - mArgs =args; + mArgs = args; mLevel = loglevel; } - public LogItem(LogLevel loglevel, String msg) { - mLevel = loglevel; - mMessage = msg; - } + public LogItem(LogLevel loglevel, String msg) { + mLevel = loglevel; + mMessage = msg; + } - public LogItem(LogLevel loglevel, int ressourceId) { - mRessourceId =ressourceId; - mLevel = loglevel; - } + public LogItem(LogLevel loglevel, int ressourceId) { + mRessourceId = ressourceId; + mLevel = loglevel; + } - public String getString(Context c) { + public String getString(Context c) { try { - if(mMessage !=null) { - return mMessage; - } else { - if(c!=null) { - if(mRessourceId==R.string.mobile_info) - return getMobileInfoString(c); - if(mArgs == null) - return c.getString(mRessourceId); - else - return c.getString(mRessourceId,mArgs); - } else { - String str = String.format(Locale.ENGLISH,"Log (no context) resid %d", mRessourceId); - if(mArgs !=null) - for(Object o:mArgs) - str += "|" + o.toString(); - - return str; - } - } + if (mMessage != null) { + return mMessage; + } else { + if (c != null) { + if (mRessourceId == R.string.mobile_info) + return getMobileInfoString(c); + if (mArgs == null) + return c.getString(mRessourceId); + else + return c.getString(mRessourceId, mArgs); + } else { + String str = String.format(Locale.ENGLISH, "Log (no context) resid %d", mRessourceId); + if (mArgs != null) + str += TextUtils.join("|", mArgs); + + + return str; + } + } } catch (UnknownFormatConversionException e) { if (c != null) throw new UnknownFormatConversionException(e.getLocalizedMessage() + getString(null)); @@ -235,68 +242,66 @@ public class VpnStatus { throw e; } catch (java.util.FormatFlagsConversionMismatchException e) { if (c != null) - throw new FormatFlagsConversionMismatchException(e.getLocalizedMessage() + getString(null),e.getConversion()); + throw new FormatFlagsConversionMismatchException(e.getLocalizedMessage() + getString(null), e.getConversion()); else throw e; } - } + } - public LogLevel getLogLevel() - { + public LogLevel getLogLevel() { return mLevel; } // The lint is wrong here - @SuppressLint("StringFormatMatches") - private String getMobileInfoString(Context c) { - c.getPackageManager(); - String apksign="error getting package signature"; - - String version="error getting version"; - try { - Signature raw = c.getPackageManager().getPackageInfo(c.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0]; - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] der = cert.getEncoded(); - md.update(der); - byte[] digest = md.digest(); - - if (Arrays.equals(digest, officalkey)) - apksign = c.getString(R.string.official_build); - else if (Arrays.equals(digest, officaldebugkey)) - apksign = c.getString(R.string.debug_build); - else if (Arrays.equals(digest, amazonkey)) - apksign = "amazon version"; - else if (Arrays.equals(digest, fdroidkey)) + @SuppressLint("StringFormatMatches") + private String getMobileInfoString(Context c) { + c.getPackageManager(); + String apksign = "error getting package signature"; + + String version = "error getting version"; + try { + Signature raw = c.getPackageManager().getPackageInfo(c.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0]; + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] der = cert.getEncoded(); + md.update(der); + byte[] digest = md.digest(); + + if (Arrays.equals(digest, officalkey)) + apksign = c.getString(R.string.official_build); + else if (Arrays.equals(digest, officaldebugkey)) + apksign = c.getString(R.string.debug_build); + else if (Arrays.equals(digest, amazonkey)) + apksign = "amazon version"; + else if (Arrays.equals(digest, fdroidkey)) apksign = "F-Droid built and signed version"; else - apksign = c.getString(R.string.built_by,cert.getSubjectX500Principal().getName()); + apksign = c.getString(R.string.built_by, cert.getSubjectX500Principal().getName()); - PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); - version = packageinfo.versionName; + PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); + version = packageinfo.versionName; - } catch (NameNotFoundException e) { - } catch (CertificateException e) { - } catch (NoSuchAlgorithmException e) { - } + } catch (NameNotFoundException | CertificateException | + NoSuchAlgorithmException ignored) { + } - Object[] argsext = Arrays.copyOf(mArgs, mArgs.length+2); - argsext[argsext.length-1]=apksign; - argsext[argsext.length-2]=version; + Object[] argsext = Arrays.copyOf(mArgs, mArgs.length + 2); + argsext[argsext.length - 1] = apksign; + argsext[argsext.length - 2] = version; - return c.getString(R.string.mobile_info_extended, argsext); + return c.getString(R.string.mobile_info_extended, argsext); - } + } - public long getLogtime() { - return logtime; - } + public long getLogtime() { + return logtime; + } public int getVerbosityLevel() { - if (mVerbosityLevel==-1) { + if (mVerbosityLevel == -1) { // Hack: // For message not from OpenVPN, report the status level as log level return mLevel.getInt(); @@ -305,90 +310,93 @@ public class VpnStatus { } } + public void saveLogToDisk(Context c) { + + File logOut = new File(c.getCacheDir(), "log.xml"); + + } + + public interface LogListener { + void newLog(LogItem logItem); + } + + public interface StateListener { + void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level); + } + + public interface ByteCountListener { + void updateByteCount(long in, long out, long diffIn, long diffOut); + } + + public synchronized static void logMessage(LogLevel level, String prefix, String message) { + newLogItem(new LogItem(level, prefix + message)); + + } + + public synchronized static void clearLog() { + logbuffer.clear(); + logInformation(); + } + + private static void logInformation() { + logInfo(R.string.mobile_info, Build.MODEL, Build.BOARD, Build.BRAND, Build.VERSION.SDK_INT); + } + + public synchronized static void addLogListener(LogListener ll) { + logListener.add(ll); + } + + public synchronized static void removeLogListener(LogListener ll) { + logListener.remove(ll); + } + + public synchronized static void addByteCountListener(ByteCountListener bcl) { + bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]); + byteCountListener.add(bcl); + } + public synchronized static void removeByteCountListener(ByteCountListener bcl) { + byteCountListener.remove(bcl); + } + + + public synchronized static void addStateListener(StateListener sl) { + if (!stateListener.contains(sl)) { + stateListener.add(sl); + if (mLaststate != null) + sl.updateState(mLaststate, mLaststatemsg, mLastStateresid, mLastLevel); + } + } - public interface LogListener { - void newLog(LogItem logItem); - } - - public interface StateListener { - void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level); - } - - public interface ByteCountListener { - void updateByteCount(long in, long out, long diffIn, long diffOut); - } - - public synchronized static void logMessage(LogLevel level,String prefix, String message) - { - newLogItem(new LogItem(level, prefix + message)); - - } - - public synchronized static void clearLog() { - logbuffer.clear(); - logInformation(); - } - - private static void logInformation() { - logInfo(R.string.mobile_info,Build.MODEL, Build.BOARD,Build.BRAND,Build.VERSION.SDK_INT); - } - - public synchronized static void addLogListener(LogListener ll){ - logListener.add(ll); - } - - public synchronized static void removeLogListener(LogListener ll) { - logListener.remove(ll); - } - - public synchronized static void addByteCountListener(ByteCountListener bcl) { - bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]); - byteCountListener.add(bcl); - } - - public synchronized static void removeByteCountListener(ByteCountListener bcl) { - byteCountListener.remove(bcl); - } - - - public synchronized static void addStateListener(StateListener sl){ - if(!stateListener.contains(sl)){ - stateListener.add(sl); - if(mLaststate!=null) - sl.updateState(mLaststate, mLaststatemsg, mLastStateresid, mLastLevel); - } - } - - private static int getLocalizedState(String state){ - if (state.equals("CONNECTING")) - return R.string.state_connecting; - else if (state.equals("WAIT")) - return R.string.state_wait; - else if (state.equals("AUTH")) - return R.string.state_auth; - else if (state.equals("GET_CONFIG")) - return R.string.state_get_config; - else if (state.equals("ASSIGN_IP")) - return R.string.state_assign_ip; - else if (state.equals("ADD_ROUTES")) - return R.string.state_add_routes; - else if (state.equals("CONNECTED")) - return R.string.state_connected; - else if (state.equals("DISCONNECTED")) - return R.string.state_disconnected; - else if (state.equals("RECONNECTING")) - return R.string.state_reconnecting; - else if (state.equals("EXITING")) - return R.string.state_exiting; - else if (state.equals("RESOLVE")) - return R.string.state_resolve; - else if (state.equals("TCP_CONNECT")) - return R.string.state_tcp_connect; - else - return R.string.unknown_state; - - } + private static int getLocalizedState(String state) { + if (state.equals("CONNECTING")) + return R.string.state_connecting; + else if (state.equals("WAIT")) + return R.string.state_wait; + else if (state.equals("AUTH")) + return R.string.state_auth; + else if (state.equals("GET_CONFIG")) + return R.string.state_get_config; + else if (state.equals("ASSIGN_IP")) + return R.string.state_assign_ip; + else if (state.equals("ADD_ROUTES")) + return R.string.state_add_routes; + else if (state.equals("CONNECTED")) + return R.string.state_connected; + else if (state.equals("DISCONNECTED")) + return R.string.state_disconnected; + else if (state.equals("RECONNECTING")) + return R.string.state_reconnecting; + else if (state.equals("EXITING")) + return R.string.state_exiting; + else if (state.equals("RESOLVE")) + return R.string.state_resolve; + else if (state.equals("TCP_CONNECT")) + return R.string.state_tcp_connect; + else + return R.string.unknown_state; + + } public static void updateStatePause(OpenVPNManagement.pauseReason pauseReason) { switch (pauseReason) { @@ -405,88 +413,84 @@ public class VpnStatus { } - private static ConnectionStatus getLevel(String state){ - String[] noreplyet = {"CONNECTING","WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"}; - String[] reply = {"AUTH","GET_CONFIG","ASSIGN_IP","ADD_ROUTES"}; - String[] connected = {"CONNECTED"}; - String[] notconnected = {"DISCONNECTED", "EXITING"}; - - for(String x:noreplyet) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; - - for(String x:reply) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED; + private static ConnectionStatus getLevel(String state) { + String[] noreplyet = {"CONNECTING", "WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"}; + String[] reply = {"AUTH", "GET_CONFIG", "ASSIGN_IP", "ADD_ROUTES"}; + String[] connected = {"CONNECTED"}; + String[] notconnected = {"DISCONNECTED", "EXITING"}; - for(String x:connected) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTED; + for (String x : noreplyet) + if (state.equals(x)) + return ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; - for(String x:notconnected) - if(state.equals(x)) - return ConnectionStatus.LEVEL_NOTCONNECTED; + for (String x : reply) + if (state.equals(x)) + return ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED; - return ConnectionStatus.UNKNOWN_LEVEL; + for (String x : connected) + if (state.equals(x)) + return ConnectionStatus.LEVEL_CONNECTED; - } + for (String x : notconnected) + if (state.equals(x)) + return ConnectionStatus.LEVEL_NOTCONNECTED; + return ConnectionStatus.UNKNOWN_LEVEL; + } - public synchronized static void removeStateListener(StateListener sl) { - stateListener.remove(sl); - } + public synchronized static void removeStateListener(StateListener sl) { + stateListener.remove(sl); + } - synchronized public static LogItem[] getlogbuffer() { + synchronized public static LogItem[] getlogbuffer() { - // The stoned way of java to return an array from a vector - // brought to you by eclipse auto complete - return logbuffer.toArray(new LogItem[logbuffer.size()]); + // The stoned way of java to return an array from a vector + // brought to you by eclipse auto complete + return logbuffer.toArray(new LogItem[logbuffer.size()]); - } + } - public static void updateStateString (String state, String msg) { - int rid = getLocalizedState(state); - ConnectionStatus level = getLevel(state); - updateStateString(state, msg, rid, level); - } + public static void updateStateString(String state, String msg) { + int rid = getLocalizedState(state); + ConnectionStatus level = getLevel(state); + updateStateString(state, msg, rid, level); + } - public synchronized static void updateStateString(String state, String msg, int resid, ConnectionStatus level) { + public synchronized static void updateStateString(String state, String msg, int resid, ConnectionStatus level) { // Workound for OpenVPN doing AUTH and wait and being connected // Simply ignore these state if (mLastLevel == ConnectionStatus.LEVEL_CONNECTED && - (state.equals("WAIT") || state.equals("AUTH"))) - { - newLogItem(new LogItem((LogLevel.DEBUG), String.format("Ignoring OpenVPN Status in CONNECTED state (%s->%s): %s",state,level.toString(),msg))); + (state.equals("WAIT") || state.equals("AUTH"))) { + newLogItem(new LogItem((LogLevel.DEBUG), String.format("Ignoring OpenVPN Status in CONNECTED state (%s->%s): %s", state, level.toString(), msg))); return; } - mLaststate= state; - mLaststatemsg = msg; - mLastStateresid = resid; - mLastLevel = level; - + mLaststate = state; + mLaststatemsg = msg; + mLastStateresid = resid; + mLastLevel = level; for (StateListener sl : stateListener) { - sl.updateState(state,msg,resid,level); - } + sl.updateState(state, msg, resid, level); + } //newLogItem(new LogItem((LogLevel.DEBUG), String.format("New OpenVPN Status (%s->%s): %s",state,level.toString(),msg))); - } + } - public static void logInfo(String message) { - newLogItem(new LogItem(LogLevel.INFO, message)); - } + public static void logInfo(String message) { + newLogItem(new LogItem(LogLevel.INFO, message)); + } public static void logDebug(String message) { newLogItem(new LogItem(LogLevel.DEBUG, message)); } public static void logInfo(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.INFO, resourceId, args)); - } + newLogItem(new LogItem(LogLevel.INFO, resourceId, args)); + } public static void logDebug(int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.DEBUG, resourceId, args)); @@ -494,19 +498,19 @@ public class VpnStatus { private synchronized static void newLogItem(LogItem logItem) { - logbuffer.addLast(logItem); - if(logbuffer.size()>MAXLOGENTRIES) - logbuffer.removeFirst(); + logbuffer.addLast(logItem); + if (logbuffer.size() > MAXLOGENTRIES) + logbuffer.removeFirst(); - for (LogListener ll : logListener) { - ll.newLog(logItem); - } - } + for (LogListener ll : logListener) { + ll.newLog(logItem); + } + } - public static void logError(String msg) { - newLogItem(new LogItem(LogLevel.ERROR, msg)); + public static void logError(String msg) { + newLogItem(new LogItem(LogLevel.ERROR, msg)); - } + } public static void logWarning(int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.WARNING, resourceId, args)); @@ -518,11 +522,12 @@ public class VpnStatus { public static void logError(int resourceId) { - newLogItem(new LogItem(LogLevel.ERROR, resourceId)); - } - public static void logError(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.ERROR, resourceId, args)); - } + newLogItem(new LogItem(LogLevel.ERROR, resourceId)); + } + + public static void logError(int resourceId, Object... args) { + newLogItem(new LogItem(LogLevel.ERROR, resourceId, args)); + } public static void logMessageOpenVPN(LogLevel level, int ovpnlevel, String message) { newLogItem(new LogItem(level, ovpnlevel, message)); @@ -531,19 +536,17 @@ public class VpnStatus { public static synchronized void updateByteCount(long in, long out) { - long lastIn = mlastByteCount[0]; - long lastOut = mlastByteCount[1]; - long diffIn = mlastByteCount[2] = in - lastIn; - long diffOut = mlastByteCount[3] = out - lastOut; - - - - mlastByteCount = new long[] {in,out,diffIn,diffOut}; - for(ByteCountListener bcl:byteCountListener){ - bcl.updateByteCount(in, out, diffIn,diffOut); - } - } + long lastIn = mlastByteCount[0]; + long lastOut = mlastByteCount[1]; + long diffIn = mlastByteCount[2] = in - lastIn; + long diffOut = mlastByteCount[3] = out - lastOut; + + mlastByteCount = new long[]{in, out, diffIn, diffOut}; + for (ByteCountListener bcl : byteCountListener) { + bcl.updateByteCount(in, out, diffIn, diffOut); + } + } } diff --git a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java index 92bf9ad3..2a75c15e 100644 --- a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java +++ b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java @@ -5,8 +5,6 @@ package de.blinkt.openvpn.fragments; -import se.leap.bitmaskclient.R; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; diff --git a/app/src/main/java/org/spongycastle/util/encoders/Base64.java b/app/src/main/java/org/spongycastle/util/encoders/Base64.java index 87bd80a0..0993e7be 100644 --- a/app/src/main/java/org/spongycastle/util/encoders/Base64.java +++ b/app/src/main/java/org/spongycastle/util/encoders/Base64.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.encoders; import java.io.ByteArrayOutputStream; diff --git a/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java b/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java index 84060707..4248bb8b 100644 --- a/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java +++ b/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.encoders; import java.io.IOException; diff --git a/app/src/main/java/org/spongycastle/util/encoders/Encoder.java b/app/src/main/java/org/spongycastle/util/encoders/Encoder.java index 106c36b7..2007ac3e 100644 --- a/app/src/main/java/org/spongycastle/util/encoders/Encoder.java +++ b/app/src/main/java/org/spongycastle/util/encoders/Encoder.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.encoders; import java.io.IOException; diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java b/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java index 0127ca0c..b9474ed3 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; import java.io.IOException; diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java b/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java index 4adb815e..6d655c87 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; public class PemHeader diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java b/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java index 6f7c79c5..59186e09 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; import java.util.ArrayList; diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java b/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java index 1a8cea6d..ddce091c 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; public interface PemObjectGenerator diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java b/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java index cbbebab9..0b3b55c4 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; import java.io.BufferedReader; @@ -49,7 +54,7 @@ public class PemReader { String line; String endMarker = END + type; - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); List headers = new ArrayList(); while ((line = readLine()) != null) diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java b/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java index f5a6a363..25730efd 100644 --- a/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java +++ b/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + package org.spongycastle.util.io.pem; import java.io.BufferedWriter; diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index ee64a1b3..bdc36e89 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -29,11 +29,10 @@ import org.jetbrains.annotations.*; import org.json.*; import java.net.*; -import java.util.*; import butterknife.*; -import de.blinkt.openvpn.activities.*; import se.leap.bitmaskclient.eip.*; +import se.leap.bitmaskclient.userstatus.*; /** * The main user facing Activity of Bitmask Android, consisting of status, controls, @@ -42,7 +41,7 @@ import se.leap.bitmaskclient.eip.*; * @author Sean Leonard <meanderingcode@aetherislands.net> * @author parmegv */ -public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver, Observer { +public class Dashboard extends Activity implements ProviderAPIResultReceiver.Receiver { protected static final int CONFIGURE_LEAP = 0; protected static final int SWITCH_PROVIDER = 1; @@ -62,14 +61,10 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn @InjectView(R.id.providerName) TextView provider_name; - @InjectView(R.id.user_session_status) - TextView user_session_status_text_view; - @InjectView(R.id.user_session_status_progress) - ProgressBar user_session_status_progress_bar; - - EipFragment eip_fragment; - private Provider provider; - private UserSessionStatus user_session_status; + + VpnFragment eip_fragment; + UserStatusFragment user_status_fragment; + private static Provider provider = new Provider(); public ProviderAPIResultReceiver providerAPI_result_receiver; private boolean switching_provider; @@ -78,21 +73,23 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn super.onCreate(savedInstanceState); app = this; - user_session_status = UserSessionStatus.getInstance(); - user_session_status.addObserver(this); PRNGFixes.apply(); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); fragment_manager = new FragmentManagerEnhanced(getFragmentManager()); handleVersion(); + User.init(getString(R.string.default_username)); + + ProviderAPICommand.initialize(this); + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this); restoreProvider(savedInstanceState); - if (provider == null || provider.getName().isEmpty()) + if (!provider.isConfigured()) startActivityForResult(new Intent(this, ConfigurationWizard.class), CONFIGURE_LEAP); else { buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false)); - restoreSessionStatus(savedInstanceState); + user_status_fragment.restoreSessionStatus(savedInstanceState); } } @@ -101,32 +98,20 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn if (savedInstanceState.containsKey(Provider.KEY)) provider = savedInstanceState.getParcelable(Provider.KEY); } - if (provider == null && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false)) + if (!provider.isConfigured() && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false)) provider = getSavedProviderFromSharedPreferences(); } - private void restoreSessionStatus(Bundle savedInstanceState) { - if (savedInstanceState != null) - if (savedInstanceState.containsKey(UserSessionStatus.TAG)) { - UserSessionStatus.SessionStatus status = (UserSessionStatus.SessionStatus) savedInstanceState.getSerializable(UserSessionStatus.TAG); - user_session_status.updateStatus(status); - } - } - @Override protected void onSaveInstanceState(@NotNull Bundle outState) { - if (provider != null) - outState.putParcelable(Provider.KEY, provider); - if (user_session_status_text_view != null && user_session_status_text_view.getVisibility() == TextView.VISIBLE) - outState.putSerializable(UserSessionStatus.TAG, user_session_status.sessionStatus()); - + outState.putParcelable(Provider.KEY, provider); super.onSaveInstanceState(outState); } private Provider getSavedProviderFromSharedPreferences() { - Provider provider = null; + Provider provider = new Provider(); try { - provider = new Provider(new URL(preferences.getString(Provider.MAIN_URL, ""))); + provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); } catch (MalformedURLException | JSONException e) { e.printStackTrace(); @@ -161,12 +146,12 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn providerToPreferences(provider); buildDashboard(false); - invalidateOptionsMenu(); + invalidateOptionsMenuOnUiThread(); if (data.hasExtra(SessionDialog.TAG)) { sessionDialog(Bundle.EMPTY); } - } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { + } else if (resultCode == RESULT_CANCELED && data != null && data.hasExtra(ACTION_QUIT)) { finish(); } else configErrorDialog(); @@ -213,33 +198,35 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn ButterKnife.inject(this); provider_name.setText(provider.getDomain()); + + user_status_fragment = new UserStatusFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean(Provider.ALLOW_REGISTRATION, provider.allowsRegistration()); + user_status_fragment.setArguments(bundle); + fragment_manager.replace(R.id.user_status_fragment, user_status_fragment, UserStatusFragment.TAG); + if (provider.hasEIP()) { - fragment_manager.removePreviousFragment(EipFragment.TAG); - eip_fragment = new EipFragment(); + fragment_manager.removePreviousFragment(VpnFragment.TAG); + eip_fragment = new VpnFragment(); if (hide_and_turn_on_eip) { preferences.edit().remove(Dashboard.START_ON_BOOT).apply(); Bundle arguments = new Bundle(); - arguments.putBoolean(EipFragment.START_ON_BOOT, true); + arguments.putBoolean(VpnFragment.START_ON_BOOT, true); if (eip_fragment != null) eip_fragment.setArguments(arguments); } - fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG); + fragment_manager.replace(R.id.servicesCollection, eip_fragment, VpnFragment.TAG); if (hide_and_turn_on_eip) { onBackPressed(); } } - handleNewUserSessionStatus(user_session_status); } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (provider.allowsRegistration()) { menu.findItem(R.id.signup_button).setVisible(true); - - boolean logged_in = User.loggedIn(); - menu.findItem(R.id.login_button).setVisible(!logged_in); - menu.findItem(R.id.logout_button).setVisible(logged_in); } return true; } @@ -261,15 +248,9 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn return true; case R.id.switch_provider: switching_provider = true; - if (LeapSRPSession.loggedIn()) logOut(); + if (User.loggedIn()) user_status_fragment.logOut(); else switchProvider(); return true; - case R.id.login_button: - sessionDialog(Bundle.EMPTY); - return true; - case R.id.logout_button: - logOut(); - return true; case R.id.signup_button: sessionDialog(Bundle.EMPTY); return true; @@ -284,131 +265,22 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn } public void showLog() { - Intent startLW = new Intent(getContext(), LogWindow.class); - startActivity(startLW); - } - - @Override - public void signUp(String username, String password) { - User.setUserName(username); - Bundle parameters = bundlePassword(password); - providerApiCommand(parameters, 0, ProviderAPI.SIGN_UP); - } - - @Override - public void logIn(String username, String password) { - User.setUserName(username); - Bundle parameters = bundlePassword(password); - providerApiCommand(parameters, 0, ProviderAPI.LOG_IN); - } - - public void logOut() { - providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.LOG_OUT); - } - - @Override - public void update(Observable observable, Object data) { - if (observable instanceof UserSessionStatus) { - UserSessionStatus status = (UserSessionStatus) observable; - handleNewUserSessionStatus(status); - } - } - - private void handleNewUserSessionStatus(UserSessionStatus status) { - user_session_status = status; - if (provider.allowsRegistration()) { - if (user_session_status.inProgress()) - showUserSessionProgressBar(); - else - hideUserSessionProgressBar(); - changeSessionStatusMessage(user_session_status.toString()); - invalidateOptionsMenu(); - } - } - - private void changeSessionStatusMessage(final String message) { - runOnUiThread(new Runnable() { - @Override - public void run() { - user_session_status_text_view.setText(message); - } - }); - } - - private void showUserSessionProgressBar() { - runOnUiThread(new Runnable() { - @Override - public void run() { - user_session_status_progress_bar.setVisibility(ProgressBar.VISIBLE); - } - }); - } - - private void hideUserSessionProgressBar() { - runOnUiThread(new Runnable() { - @Override - public void run() { - user_session_status_progress_bar.setVisibility(ProgressBar.GONE); - } - }); + LogWindowWrapper log_window_wrapper = LogWindowWrapper.getInstance(getContext()); + log_window_wrapper.showLog(); } - protected void downloadVpnCertificate() { - boolean is_authenticated = LeapSRPSession.loggedIn(); + public void downloadVpnCertificate() { + boolean is_authenticated = User.loggedIn(); boolean allowed_anon = preferences.getBoolean(Constants.ALLOWED_ANON, false); if (allowed_anon || is_authenticated) - providerApiCommand(Bundle.EMPTY, R.string.downloading_certificate_message, ProviderAPI.DOWNLOAD_CERTIFICATE); + ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_CERTIFICATE, providerAPI_result_receiver); else sessionDialog(Bundle.EMPTY); - - } - - private Bundle bundlePassword(String password) { - Bundle parameters = new Bundle(); - if (!password.isEmpty()) - parameters.putString(SessionDialog.PASSWORD, password); - return parameters; - } - - protected void providerApiCommand(Bundle parameters, int progressbar_message_resId, String providerApi_action) { - if (eip_fragment != null && progressbar_message_resId != 0) { - eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE); - setStatusMessage(progressbar_message_resId); - } - - Intent command = prepareProviderAPICommand(parameters, providerApi_action); - startService(command); - } - - private Intent prepareProviderAPICommand(Bundle parameters, String action) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent command = new Intent(this, ProviderAPI.class); - - command.putExtra(ProviderAPI.PARAMETERS, parameters); - command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - command.setAction(action); - return command; - } - - public void cancelLoginOrSignup() { - EipStatus.getInstance().setConnectedOrDisconnected(); } public void sessionDialog(Bundle resultData) { - FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG); - - DialogFragment newFragment = new SessionDialog(); - if (provider.getName().equalsIgnoreCase("riseup")) { - resultData = resultData == Bundle.EMPTY ? new Bundle() : resultData; - resultData.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true); - } - if (resultData != null && !resultData.isEmpty()) { - newFragment.setArguments(resultData); - } - newFragment.show(transaction, SessionDialog.TAG); + SessionDialog.getInstance(provider, resultData).show(transaction, SessionDialog.TAG); } private void switchProvider() { @@ -424,7 +296,7 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn if (resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) { String username = resultData.getString(SessionDialog.USERNAME); String password = resultData.getString(SessionDialog.PASSWORD); - logIn(username, password); + user_status_fragment.logIn(username, password); } else if (resultCode == ProviderAPI.FAILED_SIGNUP) { sessionDialog(resultData); } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGIN) { @@ -437,7 +309,6 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn setResult(RESULT_CANCELED); } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { eip_fragment.updateEipService(); - eip_fragment.handleNewVpnCertificate(); setResult(RESULT_OK); } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); @@ -449,18 +320,24 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn } } - private void setStatusMessage(int string_resId) { - if (eip_fragment != null && eip_fragment.status_message != null) - eip_fragment.status_message.setText(string_resId); - } - public static Context getContext() { return app; } + public static Provider getProvider() { return provider; } + @Override public void startActivityForResult(Intent intent, int requestCode) { intent.putExtra(Dashboard.REQUEST_CODE, requestCode); super.startActivityForResult(intent, requestCode); } + + public void invalidateOptionsMenuOnUiThread() { + runOnUiThread(new Runnable() { + @Override + public void run() { + invalidateOptionsMenu(); + } + }); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java new file mode 100644 index 00000000..8daa7d8c --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java @@ -0,0 +1,37 @@ +package se.leap.bitmaskclient; + +import java.net.*; + +public class DefaultedURL { + private URL DEFAULT_URL; + private String default_url = "https://example.net"; + + private URL url; + + public DefaultedURL() { + try { + DEFAULT_URL = new URL(default_url); + url = DEFAULT_URL; + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + public boolean isDefault() { return url.equals(DEFAULT_URL); } + + public void setUrl(URL url) { + this.url = url; + } + + public String getDomain() { + return url.getHost(); + } + + public URL getUrl() { + return url; + } + + public String toString() { + return url.toString(); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java index b961350e..49cf3774 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java +++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java @@ -42,7 +42,6 @@ public class LeapSRPSession { final public static String AUTHORIZATION_HEADER = "Authorization"; final public static String TAG = "Leap SRP session class tag"; - private User user; private SRPParameters params; private String username; private String password; @@ -338,7 +337,7 @@ public class LeapSRPSession { return token; } - protected static boolean loggedIn() { + public static boolean loggedIn() { return !token.isEmpty(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java new file mode 100644 index 00000000..2476f6a4 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java @@ -0,0 +1,28 @@ +package se.leap.bitmaskclient; + +import android.content.*; + +import de.blinkt.openvpn.activities.*; + +public class LogWindowWrapper { + private static LogWindowWrapper instance; + + private static String TAG = LogWindowWrapper.class.getName(); + private Context context; + + public LogWindowWrapper(Context context) { + this.context = context; + } + + public void showLog() { + Intent startLW = new Intent(context, LogWindow.class); + startLW.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(startLW); + } + + public static LogWindowWrapper getInstance(Context context) { + if(instance == null) + instance = new LogWindowWrapper(context); + return instance; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index ee06a586..559b47d1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -30,8 +30,9 @@ import java.util.*; */ public final class Provider implements Parcelable { - private JSONObject definition; // Represents our Provider's provider.json - private URL main_url; + private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json + private DefaultedURL main_url = new DefaultedURL(); + private String certificate_pin = ""; final public static String API_URL = "api_uri", @@ -58,12 +59,15 @@ public final class Provider implements Parcelable { private static final String API_TERM_DEFAULT_LANGUAGE = "default_language"; protected static final String[] API_EIP_TYPES = {"openvpn"}; + public Provider() { } + public Provider(URL main_url) { - this.main_url = main_url; + this.main_url.setUrl(main_url); } - public Provider(File provider_file) { - + public Provider(URL main_url, String certificate_pin) { + this.main_url.setUrl(main_url); + this.certificate_pin = certificate_pin; } public static final Parcelable.Creator<Provider> CREATOR @@ -79,17 +83,23 @@ public final class Provider implements Parcelable { private Provider(Parcel in) { try { - main_url = new URL(in.readString()); + main_url.setUrl(new URL(in.readString())); String definition_string = in.readString(); - if (definition_string != null) + if (!definition_string.isEmpty()) definition = new JSONObject((definition_string)); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (JSONException e) { + } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } } + public boolean isConfigured() { + return !main_url.isDefault() && definition.length() > 0; + } + + protected void setUrl(URL url) { + main_url.setUrl(url); + } + protected void define(JSONObject provider_json) { definition = provider_json; } @@ -99,14 +109,16 @@ public final class Provider implements Parcelable { } protected String getDomain() { - return main_url.getHost(); + return main_url.getDomain(); } - protected URL mainUrl() { + protected DefaultedURL mainUrl() { return main_url; } - protected String getName() { + protected String certificatePin() { return certificate_pin; } + + public String getName() { // Should we pass the locale in, or query the system here? String lang = Locale.getDefault().getLanguage(); String name = ""; @@ -116,7 +128,7 @@ public final class Provider implements Parcelable { else throw new JSONException("Provider not defined"); } catch (JSONException e) { if (main_url != null) { - String host = main_url.getHost(); + String host = main_url.getDomain(); name = host.substring(0, host.indexOf(".")); } } @@ -179,7 +191,8 @@ public final class Provider implements Parcelable { @Override public void writeToParcel(Parcel parcel, int i) { - parcel.writeString(main_url.toString()); + if(main_url != null) + parcel.writeString(main_url.toString()); if (definition != null) parcel.writeString(definition.toString()); } @@ -188,7 +201,7 @@ public final class Provider implements Parcelable { public boolean equals(Object o) { if (o instanceof Provider) { Provider p = (Provider) o; - return p.mainUrl().getHost().equals(mainUrl().getHost()); + return p.mainUrl().getDomain().equals(mainUrl().getDomain()); } else return false; } @@ -204,6 +217,6 @@ public final class Provider implements Parcelable { @Override public int hashCode() { - return mainUrl().getHost().hashCode(); + return mainUrl().getDomain().hashCode(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java new file mode 100644 index 00000000..0e4cfe8a --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java @@ -0,0 +1,45 @@ +package se.leap.bitmaskclient; + +import android.content.*; +import android.os.*; + +import org.jetbrains.annotations.*; + +public class ProviderAPICommand { + private static Context context; + + private static String action; + private static Bundle parameters; + private static ResultReceiver result_receiver; + + public static void initialize(Context context) { + ProviderAPICommand.context = context; + } + + private static boolean isInitialized() { + return context != null; + } + + public static void execute(Bundle parameters, @NotNull String action, @NotNull ResultReceiver result_receiver) throws IllegalStateException { + if(!isInitialized()) throw new IllegalStateException(); + + ProviderAPICommand.action = action; + ProviderAPICommand.parameters = parameters; + ProviderAPICommand.result_receiver = result_receiver; + + Intent intent = setUpIntent(); + context.startService(intent); + } + + private static Intent setUpIntent() { + Intent command = new Intent(context, ProviderAPI.class); + + command.setAction(action); + command.putExtra(ProviderAPI.PARAMETERS, parameters); + command.putExtra(ProviderAPI.RECEIVER_KEY, result_receiver); + + return command; + } + + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java index 533e5caf..9b880f89 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java @@ -26,8 +26,9 @@ import android.os.*; public class ProviderAPIResultReceiver extends ResultReceiver {
private Receiver mReceiver;
- public ProviderAPIResultReceiver(Handler handler) {
+ public ProviderAPIResultReceiver(Handler handler, Receiver receiver) {
super(handler);
+ setReceiver(receiver);
// TODO Auto-generated constructor stub
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java index 40fe8b5a..13ef9b80 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java @@ -28,7 +28,8 @@ public class ProviderManager implements AdapteeCollection<Provider> { if (instance == null) instance = new ProviderManager(assets_manager); - instance.addCustomProviders(external_files_dir); + if(external_files_dir != null) + instance.addCustomProviders(external_files_dir); return instance; } @@ -49,11 +50,14 @@ public class ProviderManager implements AdapteeCollection<Provider> { Set<Provider> providers = new HashSet<Provider>(); try { for (String file : relative_file_paths) { - String main_url = extractMainUrlFromInputStream(assets_manager.open(directory + "/" + file)); - providers.add(new Provider(new URL(main_url))); + InputStream provider_file = assets_manager.open(directory + "/" + file); + String main_url = extractMainUrlFromInputStream(provider_file); + String certificate_pin = extractCertificatePinFromInputStream(provider_file); + if(certificate_pin.isEmpty()) + providers.add(new Provider(new URL(main_url))); + else + providers.add(new Provider(new URL(main_url), certificate_pin)); } - } catch (MalformedURLException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } @@ -75,36 +79,50 @@ public class ProviderManager implements AdapteeCollection<Provider> { String main_url = extractMainUrlFromInputStream(new FileInputStream(external_files_dir.getAbsolutePath() + "/" + file)); providers.add(new Provider(new URL(main_url))); } - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { + } catch (MalformedURLException | FileNotFoundException e) { e.printStackTrace(); } return providers; } - private String extractMainUrlFromInputStream(InputStream input_stream_file_contents) { + private String extractMainUrlFromInputStream(InputStream input_stream) { String main_url = ""; - byte[] bytes = new byte[0]; + + JSONObject file_contents = inputStreamToJson(input_stream); + if(file_contents != null) + main_url = file_contents.optString(Provider.MAIN_URL); + return main_url; + } + + private String extractCertificatePinFromInputStream(InputStream input_stream) { + String certificate_pin = ""; + + JSONObject file_contents = inputStreamToJson(input_stream); + if(file_contents != null) + certificate_pin = file_contents.optString(Provider.CA_CERT_FINGERPRINT); + + return certificate_pin; + } + + private JSONObject inputStreamToJson(InputStream input_stream) { + JSONObject json = null; try { - bytes = new byte[input_stream_file_contents.available()]; - if (input_stream_file_contents.read(bytes) > 0) { - JSONObject file_contents = new JSONObject(new String(bytes)); - main_url = file_contents.getString(Provider.MAIN_URL); - } - } catch (IOException e) { - e.printStackTrace(); - } catch (JSONException e) { + byte[] bytes = new byte[input_stream.available()]; + if (input_stream.read(bytes) > 0) + json = new JSONObject(new String(bytes)); + input_stream.reset(); + } catch (IOException | JSONException e) { e.printStackTrace(); } - return main_url; + return json; } public Set<Provider> providers() { Set<Provider> all_providers = new HashSet<Provider>(); all_providers.addAll(default_providers); - all_providers.addAll(custom_providers); + if(custom_providers != null) + all_providers.addAll(custom_providers); return all_providers; } @@ -124,25 +142,27 @@ public class ProviderManager implements AdapteeCollection<Provider> { } @Override - public void add(Provider element) { + public boolean add(Provider element) { if (!default_providers.contains(element)) - custom_providers.add(element); + return custom_providers.add(element); + else return true; } @Override - public void remove(Provider element) { - custom_providers.remove(element); + public boolean remove(Object element) { + return custom_providers.remove(element); } @Override - public void addAll(Collection<Provider> elements) { - custom_providers.addAll(elements); + public boolean addAll(Collection<? extends Provider> elements) { + return custom_providers.addAll(elements); } @Override - public void removeAll(Collection<Provider> elements) { - custom_providers.removeAll(elements); - default_providers.removeAll(elements); + public boolean removeAll(Collection<?> elements) { + if(!elements.getClass().equals(Provider.class)) + return false; + return default_providers.removeAll(elements) || custom_providers.removeAll(elements); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java b/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java deleted file mode 100644 index e43c8a25..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import android.os.*; - -import java.util.*; - -public class UserSessionStatus extends Observable { - public static String TAG = UserSessionStatus.class.getSimpleName(); - private static UserSessionStatus current_status; - - public enum SessionStatus { - LOGGED_IN, - LOGGED_OUT, - NOT_LOGGED_IN, - DIDNT_LOG_OUT, - LOGGING_IN, - LOGGING_OUT, - SIGNING_UP - } - - private static SessionStatus session_status = SessionStatus.NOT_LOGGED_IN; - - public static UserSessionStatus getInstance() { - if (current_status == null) { - current_status = new UserSessionStatus(); - } - return current_status; - } - - private UserSessionStatus() { - } - - private void sessionStatus(SessionStatus session_status) { - this.session_status = session_status; - } - - public SessionStatus sessionStatus() { - return session_status; - } - - public boolean inProgress() { - return session_status == SessionStatus.LOGGING_IN - || session_status == SessionStatus.LOGGING_OUT; - } - - public static void updateStatus(SessionStatus session_status) { - current_status = getInstance(); - current_status.sessionStatus(session_status); - current_status.setChanged(); - current_status.notifyObservers(); - } - - @Override - public String toString() { - String username = User.userName(); - - return username + " " + conjugateToBe(username) + " " - + session_status.toString().toLowerCase().replaceAll("_", " "); - } - - private String conjugateToBe(String subject) { - String conjugation = ""; - if(subject.equalsIgnoreCase("I")) - conjugation = "am"; - else if(subject.equalsIgnoreCase("you") || subject.equalsIgnoreCase("we")|| subject.equalsIgnoreCase("they")) - conjugation = "are"; - else conjugation = "is"; - - return conjugation; - } -} diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java index 02eedd77..2e3d7524 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java @@ -19,7 +19,6 @@ package se.leap.bitmaskclient; import android.app.*; import android.content.*; import android.os.*; -import android.util.*; import android.view.*; import android.widget.*; @@ -29,35 +28,35 @@ import java.util.*; import butterknife.*; import de.blinkt.openvpn.activities.*; +import mbanje.kurt.fabbutton.*; import se.leap.bitmaskclient.eip.*; -public class EipFragment extends Fragment implements Observer { +public class VpnFragment extends Fragment implements Observer { - public static String TAG = EipFragment.class.getSimpleName(); + public static String TAG = VpnFragment.class.getSimpleName(); - protected static final String IS_PENDING = TAG + ".is_pending"; + public static final String IS_PENDING = TAG + ".is_pending"; protected static final String IS_CONNECTED = TAG + ".is_connected"; - protected static final String STATUS_MESSAGE = TAG + ".status_message"; public static final String START_ON_BOOT = "start on boot"; - @InjectView(R.id.eipSwitch) - Switch eip_switch; - @InjectView(R.id.status_message) - TextView status_message; - @InjectView(R.id.eipProgress) - ProgressBar progress_bar; + @InjectView(R.id.vpn_Status_Image) + FabButton vpn_status_image; + @InjectView(R.id.vpn_main_button) + Button main_button; private static Dashboard dashboard; - private static EIPReceiver mEIPReceiver; + private static EIPReceiver eip_receiver; private static EipStatus eip_status; - private boolean is_starting_to_connect; private boolean wants_to_connect; public void onAttach(Activity activity) { super.onAttach(activity); dashboard = (Dashboard) activity; - dashboard.providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.DOWNLOAD_EIP_SERVICE); + ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard); + + if(eip_receiver != null) + ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver); } @Override @@ -65,7 +64,7 @@ public class EipFragment extends Fragment implements Observer { super.onCreate(savedInstanceState); eip_status = EipStatus.getInstance(); eip_status.addObserver(this); - mEIPReceiver = new EIPReceiver(new Handler()); + eip_receiver = new EIPReceiver(new Handler()); } @Override @@ -73,9 +72,6 @@ public class EipFragment extends Fragment implements Observer { View view = inflater.inflate(R.layout.eip_service_fragment, container, false); ButterKnife.inject(this, view); - if (eip_status.isConnecting()) - eip_switch.setVisibility(View.VISIBLE); - Bundle arguments = getArguments(); if (arguments != null && arguments.containsKey(START_ON_BOOT) && arguments.getBoolean(START_ON_BOOT)) startEipFromScratch(); @@ -89,8 +85,6 @@ public class EipFragment extends Fragment implements Observer { eip_status.setConnecting(); else if (savedInstanceState.getBoolean(IS_CONNECTED)) eip_status.setConnectedOrDisconnected(); - else - status_message.setText(savedInstanceState.getString(STATUS_MESSAGE)); } @Override @@ -104,25 +98,20 @@ public class EipFragment extends Fragment implements Observer { public void onSaveInstanceState(Bundle outState) { outState.putBoolean(IS_PENDING, eip_status.isConnecting()); outState.putBoolean(IS_CONNECTED, eip_status.isConnected()); - outState.putString(STATUS_MESSAGE, status_message.getText().toString()); super.onSaveInstanceState(outState); } protected void saveStatus() { - boolean is_on = eip_switch.isChecked(); + boolean is_on = eip_status.isConnected() || eip_status.isConnecting(); Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit(); } - void handleNewVpnCertificate() { - handleSwitch(!eip_switch.isEnabled()); - } - - @OnCheckedChanged(R.id.eipSwitch) - void handleSwitch(boolean isChecked) { - if (isChecked) - handleSwitchOn(); - else + @OnClick(R.id.vpn_main_button) + void handleIcon() { + if (eip_status.isConnected() || eip_status.isConnecting()) handleSwitchOff(); + else + handleSwitchOn(); saveStatus(); } @@ -156,23 +145,22 @@ public class EipFragment extends Fragment implements Observer { } else if (eip_status.isConnected()) { askToStopEIP(); } else - setDisconnectedUI(); + updateIcon(); } private void askPendingStartCancellation() { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard); alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title)) .setMessage(dashboard.getString(R.string.eip_cancel_connect_text)) - .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { + .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { askToStopEIP(); } }) - .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() { + .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - eip_switch.setChecked(true); } }) .show(); @@ -180,15 +168,8 @@ public class EipFragment extends Fragment implements Observer { public void startEipFromScratch() { wants_to_connect = false; - is_starting_to_connect = true; - progress_bar.setVisibility(View.VISIBLE); - eip_switch.setVisibility(View.VISIBLE); - String status = dashboard.getString(R.string.eip_status_start_pending); - status_message.setText(status); - - if (!eip_switch.isChecked()) { - eip_switch.setChecked(true); - } + eip_status.setConnecting(); + saveStatus(); eipCommand(Constants.ACTION_START_EIP); } @@ -206,12 +187,6 @@ public class EipFragment extends Fragment implements Observer { } protected void stopEipIfPossible() { - - hideProgressBar(); - - String message = dashboard.getString(R.string.eip_state_not_connected); - status_message.setText(message); - eipCommand(Constants.ACTION_STOP_EIP); } @@ -219,16 +194,15 @@ public class EipFragment extends Fragment implements Observer { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard); alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title)) .setMessage(dashboard.getString(R.string.eip_warning_browser_inconsistency)) - .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { + .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { stopEipIfPossible(); } }) - .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() { + .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - eip_switch.setChecked(true); } }) .show(); @@ -248,7 +222,7 @@ public class EipFragment extends Fragment implements Observer { // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? Intent vpn_intent = new Intent(dashboard.getApplicationContext(), EIP.class); vpn_intent.setAction(action); - vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver); + vpn_intent.putExtra(Constants.RECEIVER_TAG, eip_receiver); dashboard.startService(vpn_intent); } @@ -267,71 +241,42 @@ public class EipFragment extends Fragment implements Observer { } private void handleNewState(EipStatus eip_status) { - if (eip_status.wantsToDisconnect()) - setDisconnectedUI(); - else if (eip_status.isConnecting() || is_starting_to_connect) - setInProgressUI(eip_status); - else if (eip_status.isConnected()) - setConnectedUI(); - else if (eip_status.isDisconnected() && !eip_status.isConnecting()) - setDisconnectedUI(); - } + Context context = dashboard.getApplicationContext(); + String error = eip_status.lastError(5, context); - private void setConnectedUI() { - hideProgressBar(); - adjustSwitch(); - is_starting_to_connect = false; - status_message.setText(dashboard.getString(R.string.eip_state_connected)); - } - - private void setDisconnectedUI() { - hideProgressBar(); - adjustSwitch(); - if (eip_status.errorInLast(5, dashboard.getApplicationContext()) - && !status_message.getText().toString().equalsIgnoreCase(dashboard.getString(R.string.eip_state_not_connected))) { + if (!error.isEmpty()) { dashboard.showLog(); VoidVpnService.stop(); } - status_message.setText(dashboard.getString(R.string.eip_state_not_connected)); - } - - private void adjustSwitch() { - if (eip_status.isConnected() || eip_status.isConnecting() || is_starting_to_connect) { - if (!eip_switch.isChecked()) { - eip_switch.setChecked(true); + updateIcon(); + updateButton(); + } + + private void updateIcon() { + if (eip_status.isConnected() || eip_status.isConnecting()) { + if(eip_status.isConnecting()) { + vpn_status_image.showProgress(true); + vpn_status_image.setIcon(R.drawable.ic_stat_vpn_empty_halo, R.drawable.ic_stat_vpn_empty_halo); + } else { + vpn_status_image.showProgress(false); + vpn_status_image.setIcon(R.drawable.ic_stat_vpn, R.drawable.ic_stat_vpn); } } else { - - if (eip_switch.isChecked()) { - eip_switch.setChecked(false); - } + vpn_status_image.setIcon(R.drawable.ic_stat_vpn_offline, R.drawable.ic_stat_vpn_offline); + vpn_status_image.showProgress(false); } } - private void setInProgressUI(EipStatus eip_status) { - int localizedResId = eip_status.getLocalizedResId(); - String logmessage = eip_status.getLogMessage(); - String prefix = dashboard.getString(localizedResId); - - showProgressBar(); - status_message.setText(prefix + " " + logmessage); - is_starting_to_connect = false; - adjustSwitch(); - } - - private void updatingCertificateUI() { - showProgressBar(); - status_message.setText(getString(R.string.updating_certificate_message)); - } - - private void showProgressBar() { - if (progress_bar != null) - progress_bar.setVisibility(View.VISIBLE); - } - - private void hideProgressBar() { - if (progress_bar != null) - progress_bar.setVisibility(View.GONE); + private void updateButton() { + if (eip_status.isConnected() || eip_status.isConnecting()) { + if(eip_status.isConnecting()) { + main_button.setText(dashboard.getString(android.R.string.cancel)); + } else { + main_button.setText(dashboard.getString(R.string.vpn_button_turn_off)); + } + } else { + main_button.setText(dashboard.getString(R.string.vpn_button_turn_on)); + } } protected class EIPReceiver extends ResultReceiver { @@ -374,7 +319,6 @@ public class EipFragment extends Fragment implements Observer { case Activity.RESULT_OK: break; case Activity.RESULT_CANCELED: - updatingCertificateUI(); dashboard.downloadVpnCertificate(); break; } @@ -394,6 +338,6 @@ public class EipFragment extends Fragment implements Observer { public static EIPReceiver getReceiver() { - return mEIPReceiver; + return eip_receiver; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index beed7948..9ff7f1af 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -96,7 +96,7 @@ public final class EIP extends IntentService { gateway = gateways_manager.select(); if (gateway != null && gateway.getProfile() != null) { - mReceiver = EipFragment.getReceiver(); + mReceiver = VpnFragment.getReceiver(); launchActiveGateway(); tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK); } else diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index ad68f96e..4bfef1cb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -27,8 +27,11 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { private static EipStatus current_status; private static VpnStatus.ConnectionStatus level = VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; - private static boolean wants_to_disconnect = false; + private static boolean + wants_to_disconnect = false, + is_connecting = false; + int last_error_line = 0; private String state, log_message; private int localized_res_id; @@ -46,9 +49,9 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { @Override public void updateState(final String state, final String logmessage, final int localizedResId, final VpnStatus.ConnectionStatus level) { updateStatus(state, logmessage, localizedResId, level); - if (isConnected() || isDisconnected()) { + if (isConnected() || isDisconnected() || wantsToDisconnect()) { setConnectedOrDisconnected(); - } else if (isConnecting()) + } else setConnecting(); } @@ -66,10 +69,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public boolean isConnecting() { - return - !isConnected() && - !isDisconnected() && - !isPaused(); + return is_connecting; } public boolean isConnected() { @@ -85,19 +85,23 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public void setConnecting() { + is_connecting = true; + wants_to_disconnect = false; current_status.setChanged(); current_status.notifyObservers(); } public void setConnectedOrDisconnected() { + is_connecting = false; wants_to_disconnect = false; current_status.setChanged(); current_status.notifyObservers(); } public void setDisconnecting() { - wants_to_disconnect = false; + wants_to_disconnect = true; + is_connecting = false; } public String getState() { @@ -133,18 +137,30 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public boolean errorInLast(int lines, Context context) { - boolean result = false; + return !lastError(lines, context).isEmpty(); + } + + public String lastError(int lines, Context context) { + String error = ""; + String[] error_keywords = {"error", "ERROR", "fatal", "FATAL"}; VpnStatus.LogItem[] log = VpnStatus.getlogbuffer(); + if(log.length < last_error_line) + last_error_line = 0; String message = ""; for (int i = 1; i <= lines && log.length > i; i++) { - message = log[log.length - i].getString(context); + int line = log.length - i; + VpnStatus.LogItem log_item = log[line]; + message = log_item.getString(context); for (int j = 0; j < error_keywords.length; j++) - if (message.contains(error_keywords[j])) - result = true; + if (message.contains(error_keywords[j]) && line > last_error_line) { + error = message; + last_error_line = line; + } } - return result; + + return error; } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 1c64328e..f41049c5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -16,19 +16,27 @@ */ package se.leap.bitmaskclient.eip; -import android.content.*; +import android.content.Context; +import android.content.SharedPreferences; -import com.google.gson.*; -import com.google.gson.reflect.*; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; -import org.json.*; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; -import java.lang.reflect.*; -import java.util.*; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; -import de.blinkt.openvpn.*; -import de.blinkt.openvpn.core.*; -import se.leap.bitmaskclient.*; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.Connection; +import de.blinkt.openvpn.core.ProfileManager; +import se.leap.bitmaskclient.Provider; /** * @author parmegv @@ -65,7 +73,7 @@ public class GatewaysManager { } public void addFromString(String gateways) { - List<Gateway> gateways_list = new ArrayList<Gateway>(); + List<Gateway> gateways_list = new ArrayList<>(); try { gateways_list = new Gson().fromJson(gateways, list_type); } catch (JsonSyntaxException e) { @@ -75,7 +83,6 @@ public class GatewaysManager { if (gateways_list != null) { for (Gateway gateway : gateways_list) addGateway(gateway); - this.gateways.addAll(gateways_list); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java index dac92fe2..cbf0fed2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java @@ -50,6 +50,10 @@ public class VoidVpnService extends VpnService { closeFd(); } + public static boolean isRunning() throws NullPointerException { + return thread.isAlive() && fd != null; + } + private static void closeFd() { try { if (fd != null) diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java new file mode 100644 index 00000000..d1c56dee --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java @@ -0,0 +1,28 @@ +package se.leap.bitmaskclient.userstatus; + + +import android.content.Context; +import android.util.AttributeSet; + +import mbanje.kurt.fabbutton.CircleImageView; +import se.leap.bitmaskclient.R; + +public class FabButton extends mbanje.kurt.fabbutton.FabButton { + + + public FabButton(Context context) { + super(context); + } + + public FabButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FabButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private CircleImageView getImage() { + return (CircleImageView) findViewById(R.id.fabbutton_circle); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java index e92c6b7b..7dbbe059 100644 --- a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package se.leap.bitmaskclient; +package se.leap.bitmaskclient.userstatus; import android.app.*; import android.content.*; @@ -23,6 +23,9 @@ import android.view.*; import android.widget.*; import butterknife.*; +import se.leap.bitmaskclient.VpnFragment; +import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.R; /** * Implements the log in dialog, currently without progress dialog. @@ -56,8 +59,18 @@ public class SessionDialog extends DialogFragment { private static boolean is_eip_pending = false; - public SessionDialog() { - setArguments(Bundle.EMPTY); + public static SessionDialog getInstance(Provider provider, Bundle arguments) { + SessionDialog dialog = new SessionDialog(); + if (provider.getName().equalsIgnoreCase("riseup")) { + arguments = + arguments == Bundle.EMPTY ? + new Bundle() : arguments; + arguments.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true); + } + if (arguments != null && !arguments.isEmpty()) { + dialog.setArguments(arguments); + } + return dialog; } public AlertDialog onCreateDialog(Bundle savedInstanceState) { @@ -68,7 +81,7 @@ public class SessionDialog extends DialogFragment { ButterKnife.inject(this, view); Bundle arguments = getArguments(); - if (arguments != Bundle.EMPTY) { + if (arguments != Bundle.EMPTY && arguments != null) { setUp(arguments); } @@ -100,7 +113,7 @@ public class SessionDialog extends DialogFragment { } private void setUp(Bundle arguments) { - is_eip_pending = arguments.getBoolean(EipFragment.IS_PENDING, false); + is_eip_pending = arguments.getBoolean(VpnFragment.IS_PENDING, false); if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString())) password_field.setError(getString(R.string.error_not_valid_password_user_message)); else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) { @@ -114,9 +127,10 @@ public class SessionDialog extends DialogFragment { if (arguments.containsKey(ERRORS.USERNAME_MISSING.toString())) { username_field.setError(getString(R.string.username_ask)); } - if (arguments.containsKey(getString(R.string.user_message))) + if (arguments.containsKey(getString(R.string.user_message))) { user_message.setText(arguments.getString(getString(R.string.user_message))); - else if (user_message.getVisibility() != TextView.VISIBLE) + user_message.setVisibility(View.VISIBLE); + } else if (user_message.getVisibility() != TextView.VISIBLE) user_message.setVisibility(View.GONE); if (!username_field.getText().toString().isEmpty() && password_field.isFocusable()) @@ -151,8 +165,9 @@ public class SessionDialog extends DialogFragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); + try { - interface_with_Dashboard = (SessionDialogInterface) activity; + interface_with_Dashboard = (SessionDialogInterface) activity.getFragmentManager().findFragmentById(R.id.user_status_fragment);; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement LogInDialogListener"); diff --git a/app/src/main/java/se/leap/bitmaskclient/User.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java index 4bbd9a91..64ce0629 100644 --- a/app/src/main/java/se/leap/bitmaskclient/User.java +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java @@ -14,15 +14,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package se.leap.bitmaskclient; +package se.leap.bitmaskclient.userstatus; + +import se.leap.bitmaskclient.LeapSRPSession; public class User { - private static String user_name = "You"; + private static String user_name; private static User user; - public static User getInstance() { + public static User init(String default_username) { if (user == null) { user = new User(); + user.setUserName(default_username); } return user; } @@ -31,8 +34,7 @@ public class User { User.user_name = user_name; } - private User() { - } + private User() { } public static String userName() { return user_name; diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java new file mode 100644 index 00000000..90ad0ffd --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package se.leap.bitmaskclient.userstatus; + +import android.content.res.*; + +import java.util.*; + +import se.leap.bitmaskclient.R; + +public class UserStatus extends Observable { + public static String TAG = UserStatus.class.getSimpleName(); + private static UserStatus current_status; + private static Resources resources; + + public enum SessionStatus { + LOGGED_IN, + LOGGED_OUT, + NOT_LOGGED_IN, + DIDNT_LOG_OUT, + LOGGING_IN, + LOGGING_OUT, + SIGNING_UP; + + @Override + public String toString() { + int id = 0; + if(this == SessionStatus.LOGGED_IN) + id = R.string.logged_in_user_status; + else if(this == SessionStatus.LOGGED_OUT) + id = R.string.logged_out_user_status; + else if(this == SessionStatus.NOT_LOGGED_IN) + id = R.string.not_logged_in_user_status; + else if(this == SessionStatus.DIDNT_LOG_OUT) + id = R.string.didnt_log_out_user_status; + else if(this == SessionStatus.LOGGING_IN) + id = R.string.logging_in_user_status; + else if(this == SessionStatus.LOGGING_OUT) + id = R.string.logging_out_user_status; + else if(this == SessionStatus.SIGNING_UP) + id = R.string.signingup_message; + + return resources.getString(id); + } + } + + private static SessionStatus session_status = SessionStatus.LOGGED_OUT; + + public static UserStatus getInstance(Resources resources) { + if (current_status == null) { + current_status = new UserStatus(resources); + } + return current_status; + } + + private UserStatus(Resources resources) { + UserStatus.resources = resources; + } + + private void sessionStatus(SessionStatus session_status) { + this.session_status = session_status; + } + + public SessionStatus sessionStatus() { + return session_status; + } + + public boolean inProgress() { + return session_status == SessionStatus.LOGGING_IN + || session_status == SessionStatus.LOGGING_OUT; + } + + public boolean isLoggedIn() { + return session_status == SessionStatus.LOGGED_IN; + } + + public boolean isLoggedOut() { + return session_status == SessionStatus.LOGGED_OUT; + } + + public boolean notLoggedIn() { + return session_status == SessionStatus.NOT_LOGGED_IN; + } + + public boolean didntLogOut() { + return session_status == SessionStatus.DIDNT_LOG_OUT; + } + + public static void updateStatus(SessionStatus session_status, Resources resources) { + current_status = getInstance(resources); + current_status.sessionStatus(session_status); + current_status.setChanged(); + current_status.notifyObservers(); + } + + @Override + public String toString() { + String user_session_status = User.userName(); + + String default_username = resources.getString(R.string.default_username, ""); + if(user_session_status.isEmpty() && !default_username.equalsIgnoreCase("null")) user_session_status = default_username; + user_session_status += " " + session_status.toString(); + + user_session_status = user_session_status.trim(); + if(User.userName().isEmpty()) + user_session_status = capitalize(user_session_status); + return user_session_status; + } + + private String capitalize(String to_be_capitalized) { + return to_be_capitalized.substring(0,1).toUpperCase() + to_be_capitalized.substring(1); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java new file mode 100644 index 00000000..20189904 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java @@ -0,0 +1,181 @@ +package se.leap.bitmaskclient.userstatus; + +import android.app.Activity; +import android.app.Fragment; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.jetbrains.annotations.NotNull; + +import java.util.Observable; +import java.util.Observer; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import butterknife.OnClick; +import se.leap.bitmaskclient.Dashboard; +import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.ProviderAPI; +import se.leap.bitmaskclient.ProviderAPICommand; +import se.leap.bitmaskclient.ProviderAPIResultReceiver; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.eip.EipStatus; + +public class UserStatusFragment extends Fragment implements Observer, SessionDialog.SessionDialogInterface { + + public static String TAG = UserStatusFragment.class.getSimpleName(); + private static Dashboard dashboard; + private ProviderAPIResultReceiver providerAPI_result_receiver; + + @InjectView(R.id.user_status_username) + TextView username; + @InjectView(R.id.user_status_icon) + FabButton icon; + @InjectView(R.id.user_status_button) + Button button; + + private UserStatus status; + private boolean allows_registration = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + status = UserStatus.getInstance(getResources()); + status.addObserver(this); + } + + @Override + public void onSaveInstanceState(@NotNull Bundle outState) { + if (username != null && username.getVisibility() == TextView.VISIBLE) + outState.putSerializable(UserStatus.TAG, status.sessionStatus()); + + super.onSaveInstanceState(outState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.user_session_fragment, container, false); + ButterKnife.inject(this, view); + + Bundle arguments = getArguments(); + allows_registration = arguments.getBoolean(Provider.ALLOW_REGISTRATION); + handleNewStatus(status); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + dashboard = (Dashboard) activity; + + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard); + } + + public void restoreSessionStatus(Bundle savedInstanceState) { + if (savedInstanceState != null) + if (savedInstanceState.containsKey(UserStatus.TAG)) { + UserStatus.SessionStatus status = (UserStatus.SessionStatus) savedInstanceState.getSerializable(UserStatus.TAG); + this.status.updateStatus(status, getResources()); + } + } + + @OnClick(R.id.user_status_button) + public void handleButton() { + android.util.Log.d(TAG, status.toString()); + if(status.isLoggedIn()) + logOut(); + else if(status.isLoggedOut()) + dashboard.sessionDialog(Bundle.EMPTY); + else if(status.inProgress()) + cancelLoginOrSignup(); + } + + @Override + public void update(Observable observable, Object data) { + if (observable instanceof UserStatus) { + final UserStatus status = (UserStatus) observable; + dashboard.runOnUiThread(new Runnable() { + @Override + public void run() { + handleNewStatus(status); + } + }); + } + } + + private void handleNewStatus(UserStatus status) { + this.status = status; + if (allows_registration) { + if (this.status.inProgress()) + showUserSessionProgressBar(); + else + hideUserSessionProgressBar(); + changeMessage(); + updateButton(); + } + } + + private void showUserSessionProgressBar() { + icon.showProgress(true); + } + + private void hideUserSessionProgressBar() { + icon.showProgress(false); + } + + private void changeMessage() { + final String message = User.userName(); + username.setText(message); + } + + private void updateButton() { + if(status.isLoggedIn() || status.didntLogOut()) + button.setText(dashboard.getString(R.string.logout_button)); + else if(allows_registration) { + if (status.isLoggedOut() || status.notLoggedIn()) + button.setText(dashboard.getString(R.string.login_button)); + else if (status.inProgress()) + button.setText(dashboard.getString(android.R.string.cancel)); + } + } + + + @Override + public void signUp(String username, String password) { + User.setUserName(username); + Bundle parameters = bundlePassword(password); + ProviderAPICommand.execute(parameters, ProviderAPI.SIGN_UP, providerAPI_result_receiver); + } + + @Override + public void logIn(String username, String password) { + User.setUserName(username); + Bundle parameters = bundlePassword(password); + ProviderAPICommand.execute(parameters, ProviderAPI.LOG_IN, providerAPI_result_receiver); + } + + public void logOut() { + android.util.Log.d(TAG, "Log out"); + ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.LOG_OUT, providerAPI_result_receiver); + } + + public void cancelLoginOrSignup() { + EipStatus.getInstance().setConnectedOrDisconnected(); + } + + private Bundle bundlePassword(String password) { + Bundle parameters = new Bundle(); + if (!password.isEmpty()) + parameters.putString(SessionDialog.PASSWORD, password); + return parameters; + } +} |