├── .gitignore
├── COPYING
├── OpenVpnLib
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── assets
│ ├── minivpn.armeabi
│ ├── minivpn.armeabi-v7a
│ ├── minivpn.mips
│ └── minivpn.x86
├── build.xml
├── libs
│ ├── android-support-v4.jar
│ ├── armeabi
│ │ ├── libopenvpn.so
│ │ ├── libopvpnutil.so
│ │ └── libstlport_shared.so
│ └── x86
│ │ ├── libopenvpn.so
│ │ ├── libopvpnutil.so
│ │ └── libstlport_shared.so
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-xhdpi
│ │ └── notification_icon.png
│ ├── drawable-xxhdpi
│ │ └── notification_icon.png
│ ├── drawable
│ │ └── launcher.png
│ └── values
│ │ └── strings.xml
└── src
│ ├── de
│ └── blinkt
│ │ └── openvpn
│ │ ├── EclipseBuildConfig.java
│ │ ├── VpnProfile.java
│ │ └── core
│ │ ├── CIDRIP.java
│ │ ├── ConfigParser.java
│ │ ├── GetRestrictionReceiver.java
│ │ ├── ICSOpenVPNApplication.java
│ │ ├── NativeUtils.java
│ │ ├── NetworkSpace.java
│ │ ├── NetworkStateManager.java
│ │ ├── OpenVPNManagement.java
│ │ ├── OpenVPNThread.java
│ │ ├── OpenVpnManagementThread.java
│ │ ├── OpenVpnService.java
│ │ ├── PRNGFixes.java
│ │ ├── ProfileManager.java
│ │ ├── ProxyDetection.java
│ │ ├── VPNLaunchHelper.java
│ │ ├── VpnStatus.java
│ │ └── X509Utils.java
│ ├── me
│ └── disconnect
│ │ └── securefi
│ │ └── openvpnlib
│ │ └── OpenVPNImplementation.java
│ └── org
│ └── spongycastle
│ └── util
│ ├── encoders
│ ├── Base64.java
│ ├── Base64Encoder.java
│ └── Encoder.java
│ └── io
│ └── pem
│ ├── PemGenerationException.java
│ ├── PemHeader.java
│ ├── PemObject.java
│ ├── PemObjectGenerator.java
│ ├── PemReader.java
│ └── PemWriter.java
├── README.md
├── disconnect
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── ant.properties
├── assets
│ ├── fonts
│ │ ├── AvenirNextLTPro-Bold.otf
│ │ ├── AvenirNextLTPro-Demi.otf
│ │ ├── AvenirNextLTPro-Medium.otf
│ │ ├── AvenirNextLTPro-Regular.otf
│ │ └── AvenirNextLTPro-Thin.otf
│ ├── minivpn.armeabi
│ ├── minivpn.armeabi-v7a
│ ├── minivpn.mips
│ └── minivpn.x86
├── build.xml
├── ic_launcher-web.png
├── libs
│ └── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
│ ├── color
│ │ └── package_button_text_color.xml
│ ├── drawable-hdpi
│ │ ├── ic_action_cancel.png
│ │ ├── icon.png
│ │ ├── launcher.png
│ │ └── notification_icon.png
│ ├── drawable-mdpi
│ │ └── ic_action_cancel.png
│ ├── drawable-sw600dp-xhdpi
│ │ ├── background_collusion_off.png
│ │ ├── background_collusion_on.png
│ │ ├── background_pack_repeat.png
│ │ ├── ic_ad_off.png
│ │ ├── ic_ad_on.png
│ │ ├── ic_basic_off.png
│ │ ├── ic_basic_on.png
│ │ ├── ic_circle_off.png
│ │ ├── ic_circle_on.png
│ │ ├── ic_malware_off.png
│ │ └── ic_malware_on.png
│ ├── drawable-sw720dp-xhdpi
│ │ ├── background_collusion_off.png
│ │ ├── background_collusion_on.png
│ │ ├── background_pack_repeat.png
│ │ ├── ic_ad_off.png
│ │ ├── ic_ad_on.png
│ │ ├── ic_basic_off.png
│ │ ├── ic_basic_on.png
│ │ ├── ic_circle_off.png
│ │ ├── ic_circle_on.png
│ │ ├── ic_malware_off.png
│ │ └── ic_malware_on.png
│ ├── drawable-xhdpi
│ │ ├── background_collusion_off.png
│ │ ├── background_collusion_on.png
│ │ ├── background_pack_repeat.png
│ │ ├── background_sampling.png
│ │ ├── ic_action_cancel.png
│ │ ├── ic_ad_off.png
│ │ ├── ic_ad_on.png
│ │ ├── ic_basic_off.png
│ │ ├── ic_basic_on.png
│ │ ├── ic_circle_off.png
│ │ ├── ic_circle_on.png
│ │ ├── ic_disconnect.png
│ │ ├── ic_malware_off.png
│ │ ├── ic_malware_on.png
│ │ ├── icon.png
│ │ ├── launcher.png
│ │ └── notification_icon.png
│ ├── drawable-xxhdpi
│ │ ├── ic_action_cancel.png
│ │ ├── icon.png
│ │ ├── launcher.png
│ │ └── notification_icon.png
│ ├── drawable
│ │ ├── ad_button.xml
│ │ ├── basic_button.xml
│ │ ├── malware_button.xml
│ │ ├── overlay_button_shape.xml
│ │ ├── packages_background.xml
│ │ └── protect_button.xml
│ ├── layout
│ │ ├── activity_info.xml
│ │ ├── activity_main.xml
│ │ ├── connecting_overlay.xml
│ │ ├── front_screen.xml
│ │ ├── package_alert_dialog.xml
│ │ ├── startup_overlay.xml
│ │ └── web_upgrade.xml
│ ├── menu
│ │ ├── main.xml
│ │ └── web_upgrade_menu.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ ├── values-w820dp
│ │ └── dimens.xml
│ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── invisible.xml
│ │ ├── strings.xml
│ │ ├── strings_non_translate.xml
│ │ └── styles.xml
└── src
│ ├── com
│ └── android
│ │ └── vending
│ │ └── billing
│ │ └── IInAppBillingService.aidl
│ └── me
│ └── disconnect
│ └── mobile
│ ├── ConnectButton.java
│ ├── DisconnectMobileConfig.java
│ ├── DisconnectMobilePrefs.java
│ ├── FrontScreenFragment.java
│ ├── InfoActivity.java
│ ├── InvisibleActivity.java
│ ├── MainActivity.java
│ ├── PackageButton.java
│ ├── WebUpgradeActivity.java
│ ├── billing
│ ├── Base64.java
│ ├── Base64DecoderException.java
│ ├── BillingHelper.java
│ ├── BillingObserver.java
│ ├── IabException.java
│ ├── IabHelper.java
│ ├── IabResult.java
│ ├── Inventory.java
│ ├── Purchase.java
│ ├── Security.java
│ └── SkuDetails.java
│ ├── packages
│ ├── PackageAlertDialog.java
│ ├── PackageDescription.java
│ ├── PackageDescriptionManager.java
│ └── Provisioner.java
│ └── vpn
│ ├── ConnectivityReceiver.java
│ ├── SecureFiDetector.java
│ ├── SynchronizedFactory.java
│ ├── VPNProvider.java
│ └── VpnManager.java
└── engineinterface
├── .classpath
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── build.xml
├── config
└── LoggingConfig.java
├── custom_rules.xml
├── custom_rules.xml~
├── proguard-project.txt
├── project.properties
└── src
└── me
└── disconnect
└── securefi
└── engine
├── LoggingConfig.java
└── VPNImplementation.java
/.gitignore:
--------------------------------------------------------------------------------
1 | gen
2 | bin
3 | obj
4 | *.DS_Store
5 | .DS_Store
6 |
7 | # Built application files
8 | *.apk
9 | *.ap_
10 |
11 | # Files for the Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 |
20 | # Proguard folder generated by Eclipse
21 | proguard/
22 |
--------------------------------------------------------------------------------
/OpenVpnLib/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/OpenVpnLib/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | OpenVpnLib
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/OpenVpnLib/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/OpenVpnLib/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/OpenVpnLib/assets/minivpn.armeabi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/assets/minivpn.armeabi
--------------------------------------------------------------------------------
/OpenVpnLib/assets/minivpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/assets/minivpn.armeabi-v7a
--------------------------------------------------------------------------------
/OpenVpnLib/assets/minivpn.mips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/assets/minivpn.mips
--------------------------------------------------------------------------------
/OpenVpnLib/assets/minivpn.x86:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/assets/minivpn.x86
--------------------------------------------------------------------------------
/OpenVpnLib/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/OpenVpnLib/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/OpenVpnLib/libs/armeabi/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/armeabi/libopenvpn.so
--------------------------------------------------------------------------------
/OpenVpnLib/libs/armeabi/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/armeabi/libopvpnutil.so
--------------------------------------------------------------------------------
/OpenVpnLib/libs/armeabi/libstlport_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/armeabi/libstlport_shared.so
--------------------------------------------------------------------------------
/OpenVpnLib/libs/x86/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/x86/libopenvpn.so
--------------------------------------------------------------------------------
/OpenVpnLib/libs/x86/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/x86/libopvpnutil.so
--------------------------------------------------------------------------------
/OpenVpnLib/libs/x86/libstlport_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/libs/x86/libstlport_shared.so
--------------------------------------------------------------------------------
/OpenVpnLib/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/OpenVpnLib/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 | android.library.reference.1=../engineinterface
17 |
--------------------------------------------------------------------------------
/OpenVpnLib/res/drawable-xhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/res/drawable-xhdpi/notification_icon.png
--------------------------------------------------------------------------------
/OpenVpnLib/res/drawable-xxhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/res/drawable-xxhdpi/notification_icon.png
--------------------------------------------------------------------------------
/OpenVpnLib/res/drawable/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/OpenVpnLib/res/drawable/launcher.png
--------------------------------------------------------------------------------
/OpenVpnLib/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | You must select a User certificate
5 | No error found
6 | Error parsing the IPv4 address
7 | Error parsing the custom routes
8 | Route rejected by Android
9 | Disconnect
10 | On some custom ICS images the permission on /dev/tun might be wrong, or the tun module might be missing completely. For CM9 images try the fix ownership option under general settings
11 | Failed to open the tun interface
12 | "Error: "
13 | Opening tun interface:
14 | Local IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d
15 | DNS Server: %1$s, Domain: %2$s
16 | Routes: %1$s %2$s
17 | Routes excluded: %1$s %2$s
18 | VpnService routes installed: %1$s %2$s
19 | Got interface information %1$s and %2$s, assuming second address is peer address of remote. Using /32 netmask for local IP. Mode given by OpenVPN is \"%3$s\".
20 | Cannot make sense of %1$s and %2$s as IP route with CIDR netmask, using /32 as netmask.
21 | Corrected route %1$s/%2$s to %3$s/%2$s
22 | Cannot access the Android Keychain Certificates. This can be caused by a firmware upgrade or by restoring a backup of the app/app settings. Please edit the VPN and reselect the certificate under basic settings to recreate the permission to access the certificate.
23 | Refusing to open tun device without IP information
24 | PKCS12 File Encryption Key
25 | Private Key Password
26 | Password
27 | Building configuration…
28 | Network Status: %s
29 | No CA Certificate returned while reading from Android keystore. Auhtentication will probably fail.
30 | Running on %1$s (%2$s) %3$s, Android API %4$d
31 | Error signing with Android keystore key %1$s: %2$s
32 | No DNS servers being used. Name resolution may not work. Consider setting custom DNS Servers. Please also note that Android will keep using your proxy settings specified for your mobile/Wi-Fi connection when no DNS servers are set.
33 | Could not add DNS Server \"%1$s\", rejected by the system: %2$s
34 | Could not configure IP Address \"%1$s\", rejected by the system: %2$s
35 | Error getting proxy settings: %s
36 | Using proxy %1$s %2$d
37 | OpenVPN crashed unexpectedly. Please consider using the send Minidump option in the main menu
38 | Connecting
39 | Waiting for server reply
40 | Authenticating
41 | Getting client configuration
42 | Assigning IP addresses
43 | Adding routes
44 | Connected
45 | Disconnect
46 | Reconnecting
47 | Exiting
48 | Not running
49 | Resolving host names
50 | Connecting (TCP)
51 | Authentication failed
52 | Waiting for usable network
53 | ↓%2$s/s %1$s - ↑%4$s/s %3$s
54 | Connecting to VPN %s
55 | Connecting to VPN %s
56 | Some versions of Android 4.1 have problems if the name of the keystore certificate contains non alphanumeric characters (like spaces, underscores or dashes). Try to reimport the certificate without special characters
57 | Running on %1$s (%2$s) %3$s, Android API %4$d, version %5$s, %6$s
58 | built by %s
59 | debug build
60 | official build
61 | Pausing connection in screen off state: less than %1$s in %2$ss
62 | Warning: Persistent tun not enabled for this VPN. Traffic will use the normal Internet connection when the screen is off.
63 | Pause VPN
64 | Resume VPN
65 | VPN pause requested by user
66 | VPN paused - screen off
67 | Cannot display certificate information
68 | Allow changes to VPN Profiles
69 | KeyChain Access error: %s
70 | Unhandled exception: %1$s\n\n%2$s
71 | %3$s: %1$s\n\n%2$s
72 |
73 | Unknown state
74 |
75 | Currently blocking
76 | Not currently protected. Tap to protect
77 | Connecting
78 | Disconnect
79 |
80 |
81 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/EclipseBuildConfig.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn;
2 |
3 | import me.disconnect.securefi.openvpnlib.BuildConfig;
4 |
5 | public class EclipseBuildConfig {
6 | public static final boolean DEBUG = BuildConfig.DEBUG;
7 | public static final String PACKAGE_NAME = "de.blinkt.openvpn";
8 | public static final String BUILD_TYPE = "debug";
9 | public static final String FLAVOR = "normal";
10 | public static final int VERSION_CODE = 93;
11 | public static final String VERSION_NAME = "0.6.12";
12 | }
13 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/CIDRIP.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.util.Locale;
4 |
5 | class CIDRIP {
6 | String mIp;
7 | int len;
8 |
9 |
10 | public CIDRIP(String ip, String mask) {
11 | mIp = ip;
12 | long netmask = getInt(mask);
13 |
14 | // Add 33. bit to ensure the loop terminates
15 | netmask += 1l << 32;
16 |
17 | int lenZeros = 0;
18 | while ((netmask & 0x1) == 0) {
19 | lenZeros++;
20 | netmask = netmask >> 1;
21 | }
22 | // Check if rest of netmask is only 1s
23 | if (netmask != (0x1ffffffffl >> lenZeros)) {
24 | // Asume no CIDR, set /32
25 | len = 32;
26 | } else {
27 | len = 32 - lenZeros;
28 | }
29 |
30 | }
31 |
32 | public CIDRIP(String address, int prefix_length) {
33 | len = prefix_length;
34 | mIp = address;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return String.format(Locale.ENGLISH, "%s/%d", mIp, len);
40 | }
41 |
42 | public boolean normalise() {
43 | long ip = getInt(mIp);
44 |
45 | long newip = ip & (0xffffffffl << (32 - len));
46 | if (newip != ip) {
47 | mIp = String.format("%d.%d.%d.%d", (newip & 0xff000000) >> 24, (newip & 0xff0000) >> 16, (newip & 0xff00) >> 8, newip & 0xff);
48 | return true;
49 | } else {
50 | return false;
51 | }
52 | }
53 |
54 | static long getInt(String ipaddr) {
55 | String[] ipt = ipaddr.split("\\.");
56 | long ip = 0;
57 |
58 | ip += Long.parseLong(ipt[0]) << 24;
59 | ip += Integer.parseInt(ipt[1]) << 16;
60 | ip += Integer.parseInt(ipt[2]) << 8;
61 | ip += Integer.parseInt(ipt[3]);
62 |
63 | return ip;
64 | }
65 |
66 | public long getInt() {
67 | return getInt(mIp);
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/GetRestrictionReceiver.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.RestrictionEntry;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 |
12 | import java.util.ArrayList;
13 |
14 | import me.disconnect.securefi.openvpnlib.R;
15 |
16 |
17 | /**
18 | * Created by arne on 25.07.13.
19 | */
20 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
21 | public class GetRestrictionReceiver extends BroadcastReceiver {
22 | @Override
23 | public void onReceive(final Context context, Intent intent) {
24 | final PendingResult result = goAsync();
25 |
26 | new Thread() {
27 | @Override
28 | public void run() {
29 | final Bundle extras = new Bundle();
30 |
31 | ArrayList restrictionEntries = initRestrictions(context);
32 |
33 | extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, restrictionEntries);
34 | result.setResult(Activity.RESULT_OK,null,extras);
35 | result.finish();
36 | }
37 | }.run();
38 | }
39 |
40 | private ArrayList initRestrictions(Context context) {
41 | ArrayList restrictions = new ArrayList();
42 | RestrictionEntry allowChanges = new RestrictionEntry("allow_changes",false);
43 | allowChanges.setTitle(context.getString(R.string.allow_vpn_changes));
44 | restrictions.add(allowChanges);
45 |
46 | return restrictions;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/ICSOpenVPNApplication.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.app.Application;
4 |
5 | /**
6 | * Created by arne on 28.12.13.
7 | */
8 | public class ICSOpenVPNApplication extends Application {
9 | @Override
10 | public void onCreate() {
11 | super.onCreate();
12 | PRNGFixes.apply();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/NativeUtils.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.security.InvalidKeyException;
4 |
5 | public class NativeUtils {
6 | public static native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
7 | static native void jniclose(int fdint);
8 |
9 | static {
10 | System.loadLibrary("stlport_shared");
11 | System.loadLibrary("opvpnutil");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/NetworkStateManager.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.net.ConnectivityManager;
8 | import android.net.NetworkInfo;
9 | import android.net.NetworkInfo.State;
10 | import android.preference.PreferenceManager;
11 |
12 | import java.util.LinkedList;
13 |
14 | import me.disconnect.securefi.openvpnlib.R;
15 |
16 |
17 | public class NetworkStateManager {
18 | private int lastNetwork = -1;
19 | private OpenVPNManagement mManagement;
20 |
21 |
22 | connectState network = connectState.DISCONNECTED;
23 |
24 | private String lastStateMsg = null;
25 |
26 | enum connectState {
27 | SHOULDBECONNECTED,
28 | PENDINGDISCONNECT,
29 | DISCONNECTED
30 | }
31 |
32 |
33 | public NetworkStateManager(OpenVPNManagement magnagement) {
34 | super();
35 | mManagement = magnagement;
36 | }
37 |
38 |
39 | public void networkStateChange(Context context) {
40 | NetworkInfo networkInfo = getCurrentNetworkInfo(context);
41 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
42 | boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
43 |
44 |
45 | String netstatestring;
46 | if (networkInfo == null) {
47 | netstatestring = "not connected";
48 | } else {
49 | String subtype = networkInfo.getSubtypeName();
50 | if (subtype == null)
51 | subtype = "";
52 | String extrainfo = networkInfo.getExtraInfo();
53 | if (extrainfo == null)
54 | extrainfo = "";
55 |
56 | /*
57 | if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) {
58 | WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
59 | WifiInfo wifiinfo = wifiMgr.getConnectionInfo();
60 | extrainfo+=wifiinfo.getBSSID();
61 |
62 | subtype += wifiinfo.getNetworkId();
63 | }*/
64 |
65 |
66 | netstatestring = String.format("%2$s %4$s to %1$s %3$s", networkInfo.getTypeName(),
67 | networkInfo.getDetailedState(), extrainfo, subtype);
68 | }
69 |
70 | if (networkInfo != null && networkInfo.getState() == State.CONNECTED) {
71 | int newnet = networkInfo.getType();
72 | network = connectState.SHOULDBECONNECTED;
73 |
74 | if (lastNetwork != newnet) {
75 | if (sendusr1) {
76 | if (lastNetwork == -1) {
77 | mManagement.resume();
78 | } else {
79 | mManagement.reconnect();
80 | }
81 | } else {
82 | mManagement.networkChange();
83 | }
84 |
85 | lastNetwork = newnet;
86 | }
87 | } else if (networkInfo == null) {
88 | // No network coverage should be handled in the apps
89 | // connectivity receiver.
90 | }
91 |
92 |
93 | if (!netstatestring.equals(lastStateMsg))
94 | VpnStatus.logInfo(R.string.netstatus, netstatestring);
95 | lastStateMsg = netstatestring;
96 |
97 | }
98 |
99 | private NetworkInfo getCurrentNetworkInfo(Context context) {
100 | ConnectivityManager conn = (ConnectivityManager)
101 | context.getSystemService(Context.CONNECTIVITY_SERVICE);
102 |
103 | return conn.getActiveNetworkInfo();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/OpenVPNManagement.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | public interface OpenVPNManagement {
4 | enum pauseReason {
5 | noNetwork,
6 | userPause,
7 | screenOff
8 | }
9 |
10 | int mBytecountInterval =2;
11 |
12 | void reconnect();
13 |
14 | void pause(pauseReason reason);
15 |
16 | void resume();
17 |
18 | boolean stopVPN();
19 |
20 | /*
21 | * Rebind the interface
22 | */
23 | void networkChange();
24 | }
25 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/OpenVPNThread.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.util.Log;
4 | import de.blinkt.openvpn.VpnProfile;
5 | import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
6 | import de.blinkt.openvpn.core.VpnStatus.LogItem;
7 |
8 | import java.io.*;
9 | import java.text.SimpleDateFormat;
10 | import java.util.*;
11 | import java.util.Map.Entry;
12 | import java.util.regex.Matcher;
13 | import java.util.regex.Pattern;
14 |
15 | import me.disconnect.securefi.engine.LoggingConfig;
16 | import me.disconnect.securefi.openvpnlib.R;
17 |
18 | public class OpenVPNThread implements Runnable {
19 | private static final String DUMP_PATH_STRING = "Dump path: ";
20 | private static final String TAG = "OpenVPN";
21 | public static final int M_FATAL = (1 << 4);
22 | public static final int M_NONFATAL = (1 << 5);
23 | public static final int M_WARN = (1 << 6);
24 | public static final int M_DEBUG = (1 << 7);
25 | private String[] mArgv;
26 | private Process mProcess;
27 | private String mNativeDir;
28 | private OpenVpnService mService;
29 | private String mDumpPath;
30 | private Map mProcessEnv;
31 |
32 | public OpenVPNThread(OpenVpnService service,String[] argv, Map processEnv, String nativelibdir)
33 | {
34 | mArgv = argv;
35 | mNativeDir = nativelibdir;
36 | mService = service;
37 | mProcessEnv = processEnv;
38 | }
39 |
40 | public void stopProcess() {
41 | mProcess.destroy();
42 | }
43 |
44 |
45 |
46 | @Override
47 | public void run() {
48 | try {
49 | if ( LoggingConfig.LOGGING ){
50 | Log.i(TAG, "Starting openvpn");
51 | }
52 |
53 | startOpenVPNThreadArgs(mArgv, mProcessEnv);
54 |
55 | if ( LoggingConfig.LOGGING ){
56 | Log.i(TAG, "Giving up");
57 | }
58 | } catch (Exception e) {
59 | VpnStatus.logException("Starting OpenVPN Thread" ,e);
60 | if ( LoggingConfig.LOGGING ){
61 | Log.e(TAG, "OpenVPNThread Got " + e.toString());
62 | }
63 | } finally {
64 | int exitvalue = 0;
65 | try {
66 | if (mProcess!=null)
67 | exitvalue = mProcess.waitFor();
68 | } catch ( IllegalThreadStateException ite) {
69 | VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage());
70 | } catch (InterruptedException ie) {
71 | VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage());
72 | }
73 | if( exitvalue != 0)
74 | VpnStatus.logError("Process exited with exit value " + exitvalue);
75 |
76 | VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
77 | if(mDumpPath!=null) {
78 | try {
79 | BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
80 | SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.GERMAN);
81 | for(LogItem li : VpnStatus.getlogbuffer()){
82 | String time = timeformat.format(new Date(li.getLogtime()));
83 | logout.write(time +" " + li.getString(mService) + "\n");
84 | }
85 | logout.close();
86 | VpnStatus.logError(R.string.minidump_generated);
87 | } catch (IOException e) {
88 | VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage());
89 | }
90 | }
91 |
92 | mService.processDied();
93 | if ( LoggingConfig.LOGGING ){
94 | Log.i(TAG, "Exiting");
95 | }
96 | }
97 | }
98 |
99 | private void startOpenVPNThreadArgs(String[] argv, Map env) {
100 | LinkedList argvlist = new LinkedList();
101 |
102 | Collections.addAll(argvlist, argv);
103 |
104 | ProcessBuilder pb = new ProcessBuilder(argvlist);
105 | // Hack O rama
106 |
107 | String lbpath = genLibraryPath(argv, pb);
108 |
109 | pb.environment().put("LD_LIBRARY_PATH", lbpath);
110 |
111 | // Add extra variables
112 | for(Entry e:env.entrySet()){
113 | pb.environment().put(e.getKey(), e.getValue());
114 | }
115 | pb.redirectErrorStream(true);
116 | try {
117 | mProcess = pb.start();
118 | // Close the output, since we don't need it
119 | mProcess.getOutputStream().close();
120 | InputStream in = mProcess.getInputStream();
121 | BufferedReader br = new BufferedReader(new InputStreamReader(in));
122 |
123 | while( true) {
124 | String logline = br.readLine();
125 | if(logline==null)
126 | return;
127 |
128 | if ( Thread.interrupted() ){
129 | // Force stopped.
130 | stopProcess();
131 | break;
132 | }
133 |
134 | if (logline.startsWith(DUMP_PATH_STRING))
135 | mDumpPath = logline.substring(DUMP_PATH_STRING.length());
136 |
137 |
138 | // 1380308330.240114 18000002 Send to HTTP proxy: 'X-Online-Host: bla.blabla.com'
139 |
140 | Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)");
141 | Matcher m = p.matcher(logline);
142 | if(m.matches()) {
143 | int flags = Integer.parseInt(m.group(3),16);
144 | String msg = m.group(4);
145 | int logLevel = flags & 0x0F;
146 |
147 | VpnStatus.LogLevel logStatus = VpnStatus.LogLevel.INFO;
148 |
149 | if ((flags & M_FATAL) != 0)
150 | logStatus = VpnStatus.LogLevel.ERROR;
151 | else if ((flags & M_NONFATAL)!=0)
152 | logStatus = VpnStatus.LogLevel.WARNING;
153 | else if ((flags & M_WARN)!=0)
154 | logStatus = VpnStatus.LogLevel.WARNING;
155 | else if ((flags & M_DEBUG)!=0)
156 | logStatus = VpnStatus.LogLevel.VERBOSE;
157 |
158 | if (msg.startsWith("MANAGEMENT: CMD"))
159 | logLevel = Math.max(4, logLevel);
160 |
161 |
162 | VpnStatus.logMessageOpenVPN(logStatus,logLevel,msg);
163 | } else {
164 | VpnStatus.logInfo("P:" + logline);
165 | }
166 | }
167 |
168 |
169 | } catch (IOException e) {
170 | VpnStatus.logException("Error reading from output of OpenVPN process" , e);
171 | stopProcess();
172 | }
173 | }
174 |
175 | private String genLibraryPath(String[] argv, ProcessBuilder pb) {
176 | // Hack until I find a good way to get the real library path
177 | String applibpath = argv[0].replace("/cache/" + VpnProfile.MINIVPN , "/lib");
178 |
179 | String lbpath = pb.environment().get("LD_LIBRARY_PATH");
180 | if(lbpath==null)
181 | lbpath = applibpath;
182 | else
183 | lbpath = lbpath + ":" + applibpath;
184 |
185 | if (!applibpath.equals(mNativeDir)) {
186 | lbpath = lbpath + ":" + mNativeDir;
187 | }
188 | return lbpath;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/ProfileManager.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.io.FileNotFoundException;
4 | import java.io.IOException;
5 | import java.io.ObjectInputStream;
6 | import java.io.ObjectOutputStream;
7 | import java.io.StreamCorruptedException;
8 | import java.util.Collection;
9 | import java.util.HashMap;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | import de.blinkt.openvpn.VpnProfile;
14 |
15 | import android.app.Activity;
16 | import android.content.Context;
17 | import android.content.SharedPreferences;
18 | import android.content.SharedPreferences.Editor;
19 | import android.preference.PreferenceManager;
20 |
21 | public class ProfileManager {
22 | private static final String PREFS_NAME = "VPNList";
23 |
24 |
25 |
26 | private static final String ONBOOTPROFILE = "onBootProfile";
27 |
28 |
29 |
30 | private static ProfileManager instance;
31 |
32 |
33 |
34 | private static VpnProfile mLastConnectedVpn=null;
35 | private HashMap profiles=new HashMap();
36 | private static VpnProfile tmpprofile=null;
37 |
38 |
39 | private static VpnProfile get(String key) {
40 | if (tmpprofile!=null && tmpprofile.getUUIDString().equals(key))
41 | return tmpprofile;
42 |
43 | if(instance==null)
44 | return null;
45 | return instance.profiles.get(key);
46 |
47 | }
48 |
49 |
50 |
51 | private ProfileManager() { }
52 |
53 | private static void checkInstance(Context context) {
54 | if(instance == null) {
55 | instance = new ProfileManager();
56 | instance.loadVPNList(context);
57 | }
58 | }
59 |
60 | synchronized public static ProfileManager getInstance(Context context) {
61 | checkInstance(context);
62 | return instance;
63 | }
64 |
65 | public static void setConntectedVpnProfileDisconnected(Context c) {
66 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
67 | Editor prefsedit = prefs.edit();
68 | prefsedit.putString(ONBOOTPROFILE, null);
69 | prefsedit.apply();
70 |
71 | }
72 |
73 | public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) {
74 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
75 | Editor prefsedit = prefs.edit();
76 |
77 | prefsedit.putString(ONBOOTPROFILE, connectedrofile.getUUIDString());
78 | prefsedit.apply();
79 | mLastConnectedVpn=connectedrofile;
80 |
81 | }
82 |
83 | public static VpnProfile getOnBootProfile(Context c) {
84 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
85 |
86 | boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false);
87 |
88 |
89 | String mBootProfileUUID = prefs.getString(ONBOOTPROFILE,null);
90 | if(useStartOnBoot && mBootProfileUUID!=null)
91 | return get(c, mBootProfileUUID);
92 | else
93 | return null;
94 | }
95 |
96 |
97 |
98 |
99 | public Collection getProfiles() {
100 | return profiles.values();
101 | }
102 |
103 | public VpnProfile getProfileByName(String name) {
104 | for (VpnProfile vpnp : profiles.values()) {
105 | if(vpnp.getName().equals(name)) {
106 | return vpnp;
107 | }
108 | }
109 | return null;
110 | }
111 |
112 | public void saveProfileList(Context context) {
113 | SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
114 | Editor editor = sharedprefs.edit();
115 | editor.putStringSet("vpnlist", profiles.keySet());
116 |
117 | // For reasing I do not understand at all
118 | // Android saves my prefs file only one time
119 | // if I remove the debug code below :(
120 | int counter = sharedprefs.getInt("counter", 0);
121 | editor.putInt("counter", counter+1);
122 | editor.apply();
123 |
124 | }
125 |
126 | public void addProfile(VpnProfile profile) {
127 | profiles.put(profile.getUUID().toString(),profile);
128 |
129 | }
130 |
131 | public static void setTemporaryProfile(VpnProfile tmp) {
132 | ProfileManager.tmpprofile = tmp;
133 | }
134 |
135 |
136 | public void saveProfile(Context context,VpnProfile profile) {
137 | // First let basic settings save its state
138 |
139 | ObjectOutputStream vpnfile;
140 | try {
141 | vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE));
142 |
143 | vpnfile.writeObject(profile);
144 | vpnfile.flush();
145 | vpnfile.close();
146 | } catch (FileNotFoundException e) {
147 |
148 | VpnStatus.logException("saving VPN profile", e);
149 | throw new RuntimeException(e);
150 | } catch (IOException e) {
151 | VpnStatus.logException("saving VPN profile", e);
152 | throw new RuntimeException(e);
153 | }
154 | }
155 |
156 |
157 | private void loadVPNList(Context context) {
158 | profiles = new HashMap();
159 | SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
160 | Set vlist = listpref.getStringSet("vpnlist", null);
161 | Exception exp =null;
162 | if(vlist==null){
163 | vlist = new HashSet();
164 | }
165 |
166 | for (String vpnentry : vlist) {
167 | try {
168 | ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
169 | VpnProfile vp = ((VpnProfile) vpnfile.readObject());
170 |
171 | // Sanity check
172 | if(vp==null || vp.mName==null || vp.getUUID()==null)
173 | continue;
174 |
175 | vp.upgradeProfile();
176 | profiles.put(vp.getUUID().toString(), vp);
177 |
178 | } catch (StreamCorruptedException e) {
179 | exp=e;
180 | } catch (FileNotFoundException e) {
181 | exp=e;
182 | } catch (IOException e) {
183 | exp=e;
184 | } catch (ClassNotFoundException e) {
185 | exp=e;
186 | }
187 | if(exp!=null) {
188 | VpnStatus.logException("Loading VPN List",exp);
189 | }
190 | }
191 | }
192 |
193 | public int getNumberOfProfiles() {
194 | return profiles.size();
195 | }
196 |
197 |
198 |
199 | public void removeProfile(Context context,VpnProfile profile) {
200 | String vpnentry = profile.getUUID().toString();
201 | profiles.remove(vpnentry);
202 | saveProfileList(context);
203 | context.deleteFile(vpnentry + ".vp");
204 | if(mLastConnectedVpn==profile)
205 | mLastConnectedVpn=null;
206 |
207 | }
208 |
209 |
210 |
211 | public static VpnProfile get(Context context, String profileUUID) {
212 | checkInstance(context);
213 | return get(profileUUID);
214 | }
215 |
216 |
217 |
218 | public static VpnProfile getLastConnectedVpn() {
219 | return mLastConnectedVpn;
220 | }
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/ProxyDetection.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.net.InetSocketAddress;
4 | import java.net.MalformedURLException;
5 | import java.net.Proxy;
6 | import java.net.ProxySelector;
7 | import java.net.SocketAddress;
8 | import java.net.URISyntaxException;
9 | import java.net.URL;
10 | import java.util.List;
11 |
12 | import me.disconnect.securefi.openvpnlib.R;
13 |
14 | import de.blinkt.openvpn.VpnProfile;
15 |
16 | public class ProxyDetection {
17 | static SocketAddress detectProxy(VpnProfile vp) {
18 | // Construct a new url with https as protocol
19 | try {
20 | // TODO which port number is being used?
21 | URL url = new URL(String.format("https://%s:%s",vp.mServerName,vp.mServerPorts[0]));
22 | Proxy proxy = getFirstProxy(url);
23 |
24 | if(proxy==null)
25 | return null;
26 | SocketAddress addr = proxy.address();
27 | if (addr instanceof InetSocketAddress) {
28 | return addr;
29 | }
30 |
31 | } catch (MalformedURLException e) {
32 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
33 | } catch (URISyntaxException e) {
34 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
35 | }
36 | return null;
37 | }
38 |
39 | static Proxy getFirstProxy(URL url) throws URISyntaxException {
40 | System.setProperty("java.net.useSystemProxies", "true");
41 |
42 | List proxylist = ProxySelector.getDefault().select(url.toURI());
43 |
44 |
45 | if (proxylist != null) {
46 | for (Proxy proxy: proxylist) {
47 | SocketAddress addr = proxy.address();
48 |
49 | if (addr != null) {
50 | return proxy;
51 | }
52 | }
53 |
54 | }
55 | return null;
56 | }
57 | }
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/VPNLaunchHelper.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 |
8 | import me.disconnect.securefi.openvpnlib.R;
9 |
10 | import android.content.Context;
11 | import android.content.Intent;
12 | import android.os.Build;
13 | import de.blinkt.openvpn.VpnProfile;
14 |
15 | public class VPNLaunchHelper {
16 | static private boolean writeMiniVPN(Context context) {
17 | File mvpnout = new File(context.getCacheDir(),VpnProfile.MINIVPN);
18 | if (mvpnout.exists() && mvpnout.canExecute())
19 | return true;
20 |
21 | IOException e2 = null;
22 |
23 | try {
24 | InputStream mvpn;
25 |
26 | try {
27 | mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI);
28 | }
29 | catch (IOException errabi) {
30 | VpnStatus.logInfo("Failed getting assets for archicture " + Build.CPU_ABI);
31 | e2=errabi;
32 | mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI2);
33 |
34 | }
35 |
36 |
37 | FileOutputStream fout = new FileOutputStream(mvpnout);
38 |
39 | byte buf[]= new byte[4096];
40 |
41 | int lenread = mvpn.read(buf);
42 | while(lenread> 0) {
43 | fout.write(buf, 0, lenread);
44 | lenread = mvpn.read(buf);
45 | }
46 | fout.close();
47 |
48 | if(!mvpnout.setExecutable(true)) {
49 | VpnStatus.logError("Failed to set minivpn executable");
50 | return false;
51 | }
52 |
53 |
54 | return true;
55 | } catch (IOException e) {
56 | if(e2!=null)
57 | VpnStatus.logException(e2);
58 | VpnStatus.logException(e);
59 |
60 | return false;
61 | }
62 | }
63 |
64 |
65 | public static void startOpenVpn(VpnProfile startprofile, Context context) {
66 | if(!writeMiniVPN(context)) {
67 | VpnStatus.logError("Error writing minivpn binary");
68 | return;
69 | }
70 |
71 | VpnStatus.logInfo(R.string.building_configration);
72 |
73 | Intent startVPN = startprofile.prepareIntent(context);
74 | if(startVPN!=null)
75 | context.startService(startVPN);
76 |
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/de/blinkt/openvpn/core/X509Utils.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import de.blinkt.openvpn.VpnProfile;
7 | import me.disconnect.securefi.openvpnlib.R;
8 |
9 | import org.spongycastle.util.io.pem.PemObject;
10 | import org.spongycastle.util.io.pem.PemReader;
11 |
12 |
13 | import javax.security.auth.x500.X500Principal;
14 | import java.io.*;
15 | import java.lang.reflect.InvocationTargetException;
16 | import java.lang.reflect.Method;
17 | import java.security.cert.Certificate;
18 | import java.security.cert.CertificateException;
19 | import java.security.cert.CertificateFactory;
20 | import java.security.cert.X509Certificate;
21 | import java.util.Hashtable;
22 |
23 | public class X509Utils {
24 | public static Certificate getCertificateFromFile(String certfilename) throws FileNotFoundException, CertificateException {
25 | CertificateFactory certFact = CertificateFactory.getInstance("X.509");
26 |
27 | InputStream inStream;
28 |
29 | if(VpnProfile.isEmbedded(certfilename)) {
30 | // The java certifcate reader is ... kind of stupid
31 | // It does NOT ignore chars before the --BEGIN ...
32 | int subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----");
33 | subIndex = Math.max(0,subIndex);
34 | inStream = new ByteArrayInputStream(certfilename.substring(subIndex).getBytes());
35 |
36 |
37 | } else {
38 | inStream = new FileInputStream(certfilename);
39 | }
40 |
41 |
42 | return certFact.generateCertificate(inStream);
43 | }
44 |
45 | public static PemObject readPemObjectFromFile (String keyfilename) throws IOException {
46 |
47 | Reader inStream;
48 |
49 | if(VpnProfile.isEmbedded(keyfilename))
50 | inStream = new StringReader(VpnProfile.getEmbeddedContent(keyfilename));
51 | else
52 | inStream = new FileReader(new File(keyfilename));
53 |
54 | PemReader pr = new PemReader(inStream);
55 | PemObject r = pr.readPemObject();
56 | pr.close();
57 | return r;
58 | }
59 |
60 |
61 |
62 |
63 | public static String getCertificateFriendlyName (Context c, String filename) {
64 | if(!TextUtils.isEmpty(filename)) {
65 | try {
66 | X509Certificate cert = (X509Certificate) getCertificateFromFile(filename);
67 |
68 | return getCertificateFriendlyName(cert);
69 |
70 | } catch (Exception e) {
71 | VpnStatus.logError("Could not read certificate" + e.getLocalizedMessage());
72 | }
73 | }
74 | return c.getString(R.string.cannotparsecert);
75 | }
76 |
77 | public static String getCertificateFriendlyName(X509Certificate cert) {
78 | X500Principal principal = cert.getSubjectX500Principal();
79 | byte[] encodedSubject = principal.getEncoded();
80 | String friendlyName=null;
81 |
82 | /* Hack so we do not have to ship a whole Spongy/bouncycastle */
83 | Exception exp=null;
84 | try {
85 | Class X509NameClass = Class.forName("com.android.org.bouncycastle.asn1.x509.X509Name");
86 | Method getInstance = X509NameClass.getMethod("getInstance",Object.class);
87 |
88 | Hashtable defaultSymbols = (Hashtable) X509NameClass.getField("DefaultSymbols").get(X509NameClass);
89 |
90 | if (!defaultSymbols.containsKey("1.2.840.113549.1.9.1"))
91 | defaultSymbols.put("1.2.840.113549.1.9.1","eMail");
92 |
93 | Object subjectName = getInstance.invoke(X509NameClass, encodedSubject);
94 |
95 | Method toString = X509NameClass.getMethod("toString",boolean.class,Hashtable.class);
96 |
97 | friendlyName= (String) toString.invoke(subjectName,true,defaultSymbols);
98 |
99 | } catch (ClassNotFoundException e) {
100 | exp =e ;
101 | } catch (NoSuchMethodException e) {
102 | exp =e;
103 | } catch (InvocationTargetException e) {
104 | exp =e;
105 | } catch (IllegalAccessException e) {
106 | exp =e;
107 | } catch (NoSuchFieldException e) {
108 | exp =e;
109 | }
110 | if (exp!=null)
111 | VpnStatus.logException("Getting X509 Name from certificate", exp);
112 |
113 | /* Fallback if the reflection method did not work */
114 | if(friendlyName==null)
115 | friendlyName = principal.getName();
116 |
117 |
118 | // Really evil hack to decode email address
119 | // See: http://code.google.com/p/android/issues/detail?id=21531
120 |
121 | String[] parts = friendlyName.split(",");
122 | for (int i=0;i 0)
39 | {
40 | return loadObject(type);
41 | }
42 | }
43 |
44 | return null;
45 | }
46 |
47 | private PemObject loadObject(String type)
48 | throws IOException
49 | {
50 | String line;
51 | String endMarker = END + type;
52 | StringBuffer buf = new StringBuffer();
53 | List headers = new ArrayList();
54 |
55 | while ((line = readLine()) != null)
56 | {
57 | if (line.indexOf(":") >= 0)
58 | {
59 | int index = line.indexOf(':');
60 | String hdr = line.substring(0, index);
61 | String value = line.substring(index + 1).trim();
62 |
63 | headers.add(new PemHeader(hdr, value));
64 |
65 | continue;
66 | }
67 |
68 | if (line.indexOf(endMarker) != -1)
69 | {
70 | break;
71 | }
72 |
73 | buf.append(line.trim());
74 | }
75 |
76 | if (line == null)
77 | {
78 | throw new IOException(endMarker + " not found");
79 | }
80 |
81 | return new PemObject(type, headers, Base64.decode(buf.toString()));
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/OpenVpnLib/src/org/spongycastle/util/io/pem/PemWriter.java:
--------------------------------------------------------------------------------
1 | package org.spongycastle.util.io.pem;
2 |
3 | import java.io.BufferedWriter;
4 | import java.io.IOException;
5 | import java.io.Writer;
6 | import java.util.Iterator;
7 |
8 | import org.spongycastle.util.encoders.Base64;
9 |
10 | /**
11 | * A generic PEM writer, based on RFC 1421
12 | */
13 | @SuppressWarnings("all")
14 | public class PemWriter
15 | extends BufferedWriter
16 | {
17 | private static final int LINE_LENGTH = 64;
18 |
19 | private final int nlLength;
20 | private char[] buf = new char[LINE_LENGTH];
21 |
22 | /**
23 | * Base constructor.
24 | *
25 | * @param out output stream to use.
26 | */
27 | public PemWriter(Writer out)
28 | {
29 | super(out);
30 |
31 | String nl = System.getProperty("line.separator");
32 | if (nl != null)
33 | {
34 | nlLength = nl.length();
35 | }
36 | else
37 | {
38 | nlLength = 2;
39 | }
40 | }
41 |
42 | /**
43 | * Return the number of bytes or characters required to contain the
44 | * passed in object if it is PEM encoded.
45 | *
46 | * @param obj pem object to be output
47 | * @return an estimate of the number of bytes
48 | */
49 | public int getOutputSize(PemObject obj)
50 | {
51 | // BEGIN and END boundaries.
52 | int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
53 |
54 | if (!obj.getHeaders().isEmpty())
55 | {
56 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
57 | {
58 | PemHeader hdr = (PemHeader)it.next();
59 |
60 | size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
61 | }
62 |
63 | size += nlLength;
64 | }
65 |
66 | // base64 encoding
67 | int dataLen = ((obj.getContent().length + 2) / 3) * 4;
68 |
69 | size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
70 |
71 | return size;
72 | }
73 |
74 | public void writeObject(PemObjectGenerator objGen)
75 | throws IOException
76 | {
77 | PemObject obj = objGen.generate();
78 |
79 | writePreEncapsulationBoundary(obj.getType());
80 |
81 | if (!obj.getHeaders().isEmpty())
82 | {
83 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
84 | {
85 | PemHeader hdr = (PemHeader)it.next();
86 |
87 | this.write(hdr.getName());
88 | this.write(": ");
89 | this.write(hdr.getValue());
90 | this.newLine();
91 | }
92 |
93 | this.newLine();
94 | }
95 |
96 | writeEncoded(obj.getContent());
97 | writePostEncapsulationBoundary(obj.getType());
98 | }
99 |
100 | private void writeEncoded(byte[] bytes)
101 | throws IOException
102 | {
103 | bytes = Base64.encode(bytes);
104 |
105 | for (int i = 0; i < bytes.length; i += buf.length)
106 | {
107 | int index = 0;
108 |
109 | while (index != buf.length)
110 | {
111 | if ((i + index) >= bytes.length)
112 | {
113 | break;
114 | }
115 | buf[index] = (char)bytes[i + index];
116 | index++;
117 | }
118 | this.write(buf, 0, index);
119 | this.newLine();
120 | }
121 | }
122 |
123 | private void writePreEncapsulationBoundary(
124 | String type)
125 | throws IOException
126 | {
127 | this.write("-----BEGIN " + type + "-----");
128 | this.newLine();
129 | }
130 |
131 | private void writePostEncapsulationBoundary(
132 | String type)
133 | throws IOException
134 | {
135 | this.write("-----END " + type + "-----");
136 | this.newLine();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Disconnect Mobile for Android
2 |
3 | To build and connect - download, import into eclipse, and plug in your certificates!
4 |
5 | See strings_non_translate.xml for details.
6 |
7 | ## License
8 |
9 | Copyright 2014 Disconnect, Inc.
10 |
11 | This program is free software, excluding the brand features and third-party
12 | portions of the program identified in the “Exceptions” below: you can
13 | redistribute it and/or modify it under the terms of the GNU General Public
14 | License as published by the Free Software Foundation, either version 3 of the
15 | License, or (at your option) any later version.
16 |
17 | This program is distributed in the hope that it will be useful, but WITHOUT ANY
18 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 | PARTICULAR PURPOSE. See the
20 | [GNU General Public License](https://www.gnu.org/licenses/gpl.html) for more
21 | details.
22 |
23 | ## Exceptions
24 |
25 | The Disconnect logos, trademarks, domain names, and other brand features used in
26 | this program cannot be reused without permission and no license is granted
27 | thereto.
28 |
29 |
--------------------------------------------------------------------------------
/disconnect/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/disconnect/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | DisconnectMobile
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/disconnect/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/disconnect/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
39 |
40 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/disconnect/ant.properties:
--------------------------------------------------------------------------------
1 | key.store.password=MYPASSWORD
2 | key.alias.password=MYPASSWORD
3 | key.store=MYPATH
4 | key.alias=MYALIAS
5 |
--------------------------------------------------------------------------------
/disconnect/assets/fonts/AvenirNextLTPro-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/fonts/AvenirNextLTPro-Bold.otf
--------------------------------------------------------------------------------
/disconnect/assets/fonts/AvenirNextLTPro-Demi.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/fonts/AvenirNextLTPro-Demi.otf
--------------------------------------------------------------------------------
/disconnect/assets/fonts/AvenirNextLTPro-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/fonts/AvenirNextLTPro-Medium.otf
--------------------------------------------------------------------------------
/disconnect/assets/fonts/AvenirNextLTPro-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/fonts/AvenirNextLTPro-Regular.otf
--------------------------------------------------------------------------------
/disconnect/assets/fonts/AvenirNextLTPro-Thin.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/fonts/AvenirNextLTPro-Thin.otf
--------------------------------------------------------------------------------
/disconnect/assets/minivpn.armeabi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/minivpn.armeabi
--------------------------------------------------------------------------------
/disconnect/assets/minivpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/minivpn.armeabi-v7a
--------------------------------------------------------------------------------
/disconnect/assets/minivpn.mips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/minivpn.mips
--------------------------------------------------------------------------------
/disconnect/assets/minivpn.x86:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/assets/minivpn.x86
--------------------------------------------------------------------------------
/disconnect/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/disconnect/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/ic_launcher-web.png
--------------------------------------------------------------------------------
/disconnect/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/disconnect/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/disconnect/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library.reference.1=../engineinterface
16 | android.library.reference.2=../OpenVpnLib
17 |
--------------------------------------------------------------------------------
/disconnect/res/color/package_button_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/disconnect/res/drawable-hdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-hdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-hdpi/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-hdpi/launcher.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-hdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-hdpi/notification_icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-mdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-mdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/background_collusion_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/background_collusion_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/background_collusion_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/background_collusion_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/background_pack_repeat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/background_pack_repeat.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_ad_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_ad_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_ad_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_ad_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_basic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_basic_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_basic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_basic_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_circle_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_circle_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_circle_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_circle_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_malware_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_malware_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw600dp-xhdpi/ic_malware_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw600dp-xhdpi/ic_malware_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/background_collusion_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/background_collusion_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/background_collusion_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/background_collusion_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/background_pack_repeat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/background_pack_repeat.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_ad_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_ad_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_ad_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_ad_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_basic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_basic_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_basic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_basic_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_circle_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_circle_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_circle_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_circle_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_malware_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_malware_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-sw720dp-xhdpi/ic_malware_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-sw720dp-xhdpi/ic_malware_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/background_collusion_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/background_collusion_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/background_collusion_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/background_collusion_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/background_pack_repeat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/background_pack_repeat.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/background_sampling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/background_sampling.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_ad_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_ad_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_ad_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_ad_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_basic_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_basic_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_basic_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_basic_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_circle_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_circle_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_circle_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_circle_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_disconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_disconnect.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_malware_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_malware_off.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/ic_malware_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/ic_malware_on.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/launcher.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xhdpi/notification_icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xxhdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xxhdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xxhdpi/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xxhdpi/launcher.png
--------------------------------------------------------------------------------
/disconnect/res/drawable-xxhdpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/disconnectme/disconnect-mobile-android/98bed0f21cd1702f53cb9b5acca05b525bb62263/disconnect/res/drawable-xxhdpi/notification_icon.png
--------------------------------------------------------------------------------
/disconnect/res/drawable/ad_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/disconnect/res/drawable/basic_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/disconnect/res/drawable/malware_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/disconnect/res/drawable/overlay_button_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/disconnect/res/drawable/packages_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/disconnect/res/drawable/protect_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/disconnect/res/layout/activity_info.xml:
--------------------------------------------------------------------------------
1 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/disconnect/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/disconnect/res/layout/connecting_overlay.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
22 |
31 |
32 |
46 |
47 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/disconnect/res/layout/front_screen.xml:
--------------------------------------------------------------------------------
1 |
5 |
13 |
20 |
21 |
33 |
34 |
35 |
40 |
51 |
59 |
72 |
85 |
98 |
99 |
100 |
101 |
102 |
103 |
108 |
115 |
116 |
--------------------------------------------------------------------------------
/disconnect/res/layout/package_alert_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
18 |
25 |
33 |
40 |
48 |
57 |
65 |
66 |
--------------------------------------------------------------------------------
/disconnect/res/layout/startup_overlay.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/disconnect/res/layout/web_upgrade.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/disconnect/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/disconnect/res/menu/web_upgrade_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/disconnect/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/disconnect/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/disconnect/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | 64dp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/disconnect/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #009548
4 | #009548
5 | #d1e3da
6 | #31c779
7 | #c64848
8 | #afa6a6
9 | #ffffff
10 | #4f4f4f
11 | #4f4f4f
12 |
13 |
--------------------------------------------------------------------------------
/disconnect/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 | 16dp
7 |
8 |
9 |
--------------------------------------------------------------------------------
/disconnect/res/values/invisible.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/disconnect/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Disconnect
5 | Settings
6 | Protection Packs
7 | Basic
8 | Malvertising
9 | Malware
10 |
11 |
12 | You need to authorize the VPN connection. We don’t route your traffic through the VPN but this is how we block unwanted content.
13 | If you click "OK", you will next see the system dialog asking for your approval.
14 |
15 |
16 | Activate
17 | Deactivate
18 | Purchase
19 | Close
20 | Please activate a package first.
21 |
22 | Disconnect Mobile Feedback
23 |
24 | You may need to authorize the VPN connection. We don’t route your traffic through the VPN but this is how we block unwanted content.
25 | Activating Protection
26 | Cancel
27 | Blocking currently powered by Secure Wireless. Please open Secure Wireless to change any settings.
28 | Unable to display package descriptions
29 |
30 |
31 | Disconnect was founded on a basic principle: that people should have the freedom to move about the internet — and their lives — without anyone else looking over their shoulder. The company was started in 2011 by a former Google engineer and a consumer-rights attorney. Disconnect\'s top-rated apps are used by more than 2,000,000 people every week.
32 | Our privacy policy, in a sentence: We don\'t collect your personal info, except your email address if you ask us to write to you. Read our entire policy at https://disconnect.me/privacy.
33 | The Basic Privacy Pack blocks the biggest mobile trackers. It will automatically update its filter list and you can view the current filter list here: https://disconnect.me/lists/basicfilter.\n\nThe trackers we block try to collect data about your activity by sending tracking requests to your device. Most of these tracking requests are invisible. Our technology blocks these requests globally. meaning that you are protected using an app or browsing the web on 3G, 4G or Wi-Fi.\n\nThe Basic Privacy Pack works silently in the background, and you\'ll know it\'s active by the persistent notification.
34 | The Advertising Filter Pack works by blocking more than 2500 advertising services from serving ads that track you and collect your personal info. Our technology blocks these ads globally, meaning that you are protected if you are using an app or browsing the web on 3G, 4G or Wi-Fi. The app will automatically update to block additional ad trackers as we discover them. You can view the current filter list here: https://disconnect.me/lists/adfilter.\n\nThe Advertising Filter Pack works silently in the background, and you\'ll know it\'s active by the persistent notification.
35 | The Malware Protection Pack blocks thousands of websites suspected of malware, spyware, phishing scams and more. We crawl the Web looking for malware sites, verify these sites through Google\'s Safe Browsing API, and update the list often because everyday new malware sites pop up and others are taken down or are no longer a threat. List updates are automatic and you can view the current malware filter list here: https://disconnect.me/lists/malwarefilter.\n\nThe Malware Protection Pack works silently in the background, and you\'ll know it\'s active by the persistent notification.
36 |
37 | Learn More
38 | About
39 | Privacy Policy
40 | Basic privacy pack
41 | Malvertising filter pack
42 | Malware protection pack
43 | Other
44 | Send feedback
45 |
46 |
47 | Currently blocking tracking
48 | Currently blocking advertisements
49 | Currently blocking malware
50 | Currently blocking tracking and advertisements
51 | Currently blocking tracking and malware
52 | Currently blocking advertisements and malware
53 | Currently blocking tracking, advertisements and malware
54 |
55 |
--------------------------------------------------------------------------------
/disconnect/res/values/strings_non_translate.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MYCERT
5 |
6 |
7 | client\ndev tun\nproto udp\nresolv-retry infinite\nnobind\npersist-key\npersist-tun\nca ca.crt\ntls-auth ta.key 1\ncomp-lzo\nverb 3\nauth-user-pass\nremote your-endpoint.com 443\ncipher AES-256-CBC\ntls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA
8 |
9 |
10 | MYCERT
11 |
12 |
13 | MYCERT
14 |
15 |
16 | MYCERT
17 |
18 |
19 |
--------------------------------------------------------------------------------
/disconnect/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
22 |
23 |
26 |
27 |
28 |
36 |
37 |
40 |
41 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/ConnectButton.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Color;
7 | import android.util.AttributeSet;
8 | import android.view.MotionEvent;
9 | import android.widget.ToggleButton;
10 |
11 | public class ConnectButton extends ToggleButton {
12 |
13 | public ConnectButton(Context context, AttributeSet attrs, int defStyle) {
14 | super(context, attrs, defStyle);
15 | setDrawingCacheEnabled(true);
16 | }
17 |
18 | public ConnectButton(Context context, AttributeSet attrs) {
19 | super(context, attrs);
20 | setDrawingCacheEnabled(true);
21 | }
22 |
23 | public ConnectButton(Context context) {
24 | super(context);
25 | setDrawingCacheEnabled(true);
26 | }
27 |
28 | @SuppressLint("ClickableViewAccessibility")
29 | @Override
30 | public boolean onTouchEvent(MotionEvent event) {
31 | // Ignore clicks on the transparent parts of the button
32 | final int action = event.getAction();
33 | if (action == MotionEvent.ACTION_UP){
34 | Bitmap bmp = Bitmap.createBitmap(getDrawingCache());
35 | int color = 0;
36 | try {
37 | color = bmp.getPixel((int) event.getX(), (int) event.getY());
38 | } catch (Exception e) {
39 | }
40 | if (color == Color.TRANSPARENT){
41 | // If transparent ignore up event
42 | return false;
43 | }
44 | }
45 |
46 | return super.onTouchEvent(event);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/DisconnectMobileConfig.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | public class DisconnectMobileConfig {
4 |
5 | public static final String PACKAGE_PROVISIONING_URL = "https://your-endpoint.com";
6 | public static final String SERVER_GATEWAY = "your-endpoint.com";
7 | public static final String FEEDBACK_EMAIL_ADDRESS = "support@your-endpoint.com";
8 |
9 | public static final String IP_ADDRESS_IF_BLOCKED = "127.0.0.1";
10 | public static final String HOST_NAME = "mixpanel.com";
11 | public static final String ALTERNATIVE_APP_PACKAGE_NAME = "your-endpoint.com";
12 | public static final Boolean FORCE_NON_NATIVE_BILLING = false; // false by default
13 | }
14 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/DisconnectMobilePrefs.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import java.util.Calendar;
4 |
5 | import me.disconnect.securefi.engine.VPNImplementation;
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 |
9 | /*
10 | * Wrapper around the apps shared preferences
11 | */
12 | public class DisconnectMobilePrefs {
13 | private static final String ADS_PACK_PURCHASED = "ads_pack_purchased";
14 | private static final String MALWARE_PACK_PURCHASED = "malware_pack_purchased";
15 | private static final String ADS_PACK_PRICE = "ads_pack_price";
16 | private static final String MALWARE_PACK_PRICE = "malware_pack_price";
17 |
18 | public static final int BASIC_PACKAGE_ACTIVATED = 1;
19 | public static final int ADS_PACKAGE_ACTIVATED = 2;
20 | public static final int MALWARE_PACKAGE_ACTIVATED = 4;
21 | private static final String SHARED_PREFERENCES_NAME = VPNImplementation.VPN_PREFS; // SharedPreferences file name.
22 |
23 | //TODO Change access in invisible activity to use methods.
24 | public static final String PROTECTION_ON = "protection_on";
25 | private static final String KEY_GETTING_PERMISSION = VPNImplementation.KEY_GETTING_PERMISSION; // semaphore to serialize the approval process.
26 | private static final String KEY_PERMISSION_REVOKED = VPNImplementation.KEY_PERMISSION_REVOKED; // If user wants us all the way off.
27 | private static final String PACKAGES_ACTIVATED = "packages_activated";
28 |
29 | private static final String GENERATED_USERNAME = "generated_username";
30 | private static final String DATE_CHECKED = "date_checked";
31 | private static final String LAST_NOTIFICATION = "last_notification";
32 |
33 | private SharedPreferences mPreferences;
34 |
35 | public DisconnectMobilePrefs( Context aContext ){
36 | //mContext = aContext;
37 | mPreferences = aContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE );
38 | if (!mPreferences.contains(PACKAGES_ACTIVATED) ){
39 | // On first start, set the basic package as being available
40 | setBasicPackage(true);
41 | }
42 | }
43 |
44 | public boolean isProtected(){
45 | return mPreferences.getBoolean(PROTECTION_ON, false);
46 | }
47 |
48 | public void setProtection(boolean aOn){
49 | mPreferences.edit().putBoolean(PROTECTION_ON, aOn).commit();
50 | if ( aOn ){
51 |
52 | if(aOn){ // This may fix any error that might have left this flag in the wrong state.
53 | mPreferences.edit()
54 | .putBoolean(KEY_PERMISSION_REVOKED, false)
55 | .putBoolean(KEY_GETTING_PERMISSION, false)
56 | .commit();
57 | }
58 | }
59 | }
60 |
61 | public void setMalwarePackage(boolean aActivated){
62 | int packages = mPreferences.getInt(PACKAGES_ACTIVATED, 0);
63 | if ( aActivated ){
64 | packages |= MALWARE_PACKAGE_ACTIVATED;
65 | } else {
66 | packages &= ~ MALWARE_PACKAGE_ACTIVATED;
67 | }
68 |
69 | mPreferences.edit().putInt(PACKAGES_ACTIVATED, packages).commit();
70 | }
71 |
72 | public void setAdvertsPackage(boolean aActivated){
73 | int packages = mPreferences.getInt(PACKAGES_ACTIVATED, 0);
74 | if ( aActivated ){
75 | packages |= ADS_PACKAGE_ACTIVATED;
76 | } else {
77 | packages &= ~ ADS_PACKAGE_ACTIVATED;
78 | }
79 |
80 | mPreferences.edit().putInt(PACKAGES_ACTIVATED, packages).commit();
81 | }
82 |
83 | public void setBasicPackage(boolean aActivated){
84 | int packages = mPreferences.getInt(PACKAGES_ACTIVATED, 0);
85 | if ( aActivated ){
86 | packages |= BASIC_PACKAGE_ACTIVATED;
87 | } else {
88 | packages &= ~ BASIC_PACKAGE_ACTIVATED;
89 | }
90 |
91 | mPreferences.edit().putInt(PACKAGES_ACTIVATED, packages).commit();
92 | }
93 |
94 | public boolean malwarePackageAvailable(){
95 | return (mPreferences.getInt(PACKAGES_ACTIVATED, 0) & MALWARE_PACKAGE_ACTIVATED) == MALWARE_PACKAGE_ACTIVATED;
96 | }
97 |
98 | public boolean adsPackageAvailable(){
99 | return (mPreferences.getInt(PACKAGES_ACTIVATED, 0) & ADS_PACKAGE_ACTIVATED) == ADS_PACKAGE_ACTIVATED;
100 | }
101 |
102 | public boolean basicPackageAvailable(){
103 | return (mPreferences.getInt(PACKAGES_ACTIVATED, 0) & BASIC_PACKAGE_ACTIVATED) == BASIC_PACKAGE_ACTIVATED;
104 | }
105 |
106 | public int getAvailablePackages(){
107 | return mPreferences.getInt(PACKAGES_ACTIVATED, 0);
108 | }
109 |
110 | public void setMalwarePackagePurchased(boolean aPurchased){
111 | mPreferences.edit().putBoolean(MALWARE_PACK_PURCHASED, aPurchased).commit();
112 | }
113 |
114 | public void setAdvertsPackagePurchased(boolean aPurchased){
115 | mPreferences.edit().putBoolean(ADS_PACK_PURCHASED, aPurchased).commit();
116 | }
117 |
118 | public boolean malwarePackagePurchased(){
119 | return mPreferences.getBoolean(MALWARE_PACK_PURCHASED, false);
120 | }
121 |
122 | public boolean adsPackagePurchased(){
123 | return true;
124 | // return mPreferences.getBoolean(ADS_PACK_PURCHASED, false);
125 | }
126 |
127 | public boolean notificationShown(String identifier) {
128 | return mPreferences.getBoolean(identifier, false);
129 | }
130 |
131 | public void setNotificationsShown(String identifier) {
132 | mPreferences.edit().putBoolean(identifier, true).commit();
133 | }
134 |
135 | public void setLastNotificationShown(String identifier) {
136 | mPreferences.edit().putString(LAST_NOTIFICATION, identifier).commit();
137 | }
138 |
139 | public String getLastNotificationShown() {
140 | return mPreferences.getString(LAST_NOTIFICATION, "none");
141 | }
142 |
143 | public void setProtectedMessage(String aMessage){
144 | mPreferences.edit().putString(VPNImplementation.PROTECTED_MESSAGE, aMessage).commit();
145 | }
146 |
147 | public void setMalwarePackagePrice(String aPrice){
148 | mPreferences.edit().putString(MALWARE_PACK_PRICE, aPrice).commit();
149 | }
150 |
151 | public void setAdvertsPackagePrice(String aPrice){
152 | mPreferences.edit().putString(ADS_PACK_PRICE, aPrice).commit();
153 | }
154 |
155 | public String malwarePackagePrice(){
156 | return mPreferences.getString(MALWARE_PACK_PRICE, null);
157 | }
158 |
159 | public String adsPackagePrice(){
160 | return mPreferences.getString(ADS_PACK_PRICE, null);
161 | }
162 |
163 | public String generatedUsername(){
164 | return mPreferences.getString(GENERATED_USERNAME, null);
165 | }
166 |
167 | public void setGeneratedUsername(String username){
168 | mPreferences.edit().putString(GENERATED_USERNAME, username).commit();
169 | }
170 |
171 | public void setDateNotificationChecked(Calendar lastTime){
172 | mPreferences.edit().putLong(DATE_CHECKED, lastTime.getTime().getTime()).commit();
173 | }
174 |
175 | public Long getDateNotificationChecked(){
176 | return mPreferences.getLong(DATE_CHECKED, 0);
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/InfoActivity.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.widget.TextView;
7 | import me.disconnect.mobile2.R;
8 |
9 | public class InfoActivity extends Activity {
10 |
11 | private static final String INFO_TEXT = "infoText";
12 | private static final String TITLE = "title";
13 |
14 | public static void show(Activity aLaunchingActivity, int aTitleResId, int aInfoTextResId) {
15 | Intent intent = new Intent(aLaunchingActivity, InfoActivity.class);
16 | intent.putExtra(TITLE, aLaunchingActivity.getString(aTitleResId) );
17 | intent.putExtra(INFO_TEXT, aLaunchingActivity.getString( aInfoTextResId) );
18 | aLaunchingActivity.startActivity(intent);
19 | }
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_info);
25 | getActionBar().setDisplayHomeAsUpEnabled(true); // Show the Up button in the action bar.
26 |
27 | Intent intent = getIntent();
28 | String text = intent.getStringExtra(INFO_TEXT);
29 |
30 | TextView body = (TextView)findViewById(R.id.body);
31 | body.setText(text);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/InvisibleActivity.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.Dialog;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.os.Bundle;
10 | import android.support.v4.content.LocalBroadcastManager;
11 | import android.util.Log;
12 | import android.view.Window;
13 | import android.view.WindowManager;
14 | import android.widget.Toast;
15 |
16 | import me.disconnect.mobile2.R;
17 | import me.disconnect.mobile.vpn.VpnManager;
18 | import me.disconnect.securefi.engine.LoggingConfig;
19 | import me.disconnect.securefi.engine.VPNImplementation;
20 |
21 | /**
22 | * An invisible activity intended to only live long enough to display toast messages or start an Activity.
23 | * If the "Message" key is found in the intent, a Toast is shown with that key's value.
24 | * If the SecureWireless.LAUNCH_THIS key is found, the intent value will be launched via startActivityForResult().
25 | */
26 | public class InvisibleActivity extends Activity {
27 | public static final String USER_CANCELLED = "user_cancelled_connection";
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | this.requestWindowFeature(Window.FEATURE_NO_TITLE);
33 | this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
34 | String msg = getIntent().getStringExtra("Message");
35 | if(msg != null) {
36 | Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
37 | finish();
38 | }
39 | else if(getIntent().getParcelableExtra(VPNImplementation.LAUNCH_THIS) != null) {
40 | if(getSharedPreferences(VPNImplementation.VPN_PREFS, MODE_PRIVATE).getBoolean(VPNImplementation.KEY_PERMISSION_REVOKED, false))
41 | finish(); // User has opted completely out of Secure Wireless.
42 | else
43 | showPrePermissionDialog();
44 | }
45 | }
46 |
47 | private void showPrePermissionDialog() {
48 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
49 | builder.setMessage(getString(R.string.permission_instructions));
50 | builder.setPositiveButton("OK", new Dialog.OnClickListener() {
51 | @Override
52 | public void onClick(DialogInterface dialog, int which) {
53 | // The user saw the dialog text and presumably understands that they are about to
54 | // see the scary system VPN dialog and are ready to approve it.
55 | Intent permIntent = getIntent().getParcelableExtra(VPNImplementation.LAUNCH_THIS);
56 | startActivityForResult(permIntent, VPNImplementation.PREPARE_VPN_SERVICE);
57 | dialog.cancel();
58 | }
59 | });
60 | builder.setNegativeButton("No", new Dialog.OnClickListener() {
61 | @Override
62 | public void onClick(DialogInterface dialog, int which) {
63 | // The user was presented with the system dialog asking them to approve our taking
64 | // over of the VPN, and they hit cancel. Why would they cancel when they initiated
65 | // this process by turning on Secure Wireless? It doesn't matter. If we don't turn
66 | // it off in that case they will be stuck in an endless loop where their only way
67 | // out would be to approve it. That is the purpose of the pre-permission dialog.
68 | SharedPreferences.Editor edit = getSharedPreferences(VPNImplementation.VPN_PREFS, MODE_PRIVATE).edit();
69 | edit.putBoolean(VPNImplementation.KEY_PERMISSION_REVOKED, true);
70 | edit.putBoolean(DisconnectMobilePrefs.PROTECTION_ON, false); // Forcing master switch. OK because user said "No".
71 | edit.putBoolean(VPNImplementation.KEY_GETTING_PERMISSION, false);
72 | edit.commit();
73 | dialog.cancel();
74 |
75 | Intent intent = new Intent(USER_CANCELLED);
76 | LocalBroadcastManager.getInstance(InvisibleActivity.this).sendBroadcast(intent);
77 |
78 | finish();
79 | }
80 | });
81 | builder.show();
82 | }
83 |
84 | // This receives the results from when the user has been asked to approve this VPN app.
85 | // Subsequent attempts to connect to the VPN will succeed.
86 | @Override
87 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
88 | SharedPreferences.Editor editor = getSharedPreferences(VPNImplementation.VPN_PREFS, MODE_PRIVATE).edit();
89 |
90 | boolean reLaunchVPN = false;
91 | if(requestCode == VPNImplementation.PREPARE_VPN_SERVICE) {
92 | if(resultCode == 0) {
93 | // Forcing master switch. OK because user hit "Cancel".
94 | editor.putBoolean(DisconnectMobilePrefs.PROTECTION_ON, false);
95 | Intent intent = new Intent(USER_CANCELLED);
96 | LocalBroadcastManager.getInstance(InvisibleActivity.this).sendBroadcast(intent);
97 |
98 | } else if(resultCode == -1) {
99 | // User approved. We're good to go.
100 | editor.putBoolean(VPNImplementation.KEY_PERMISSION_REVOKED, false);
101 |
102 | // Start the vpn
103 | reLaunchVPN = true;
104 | }
105 | }
106 | editor.putBoolean(VPNImplementation.KEY_GETTING_PERMISSION, false);
107 | editor.commit();
108 | finish();
109 |
110 | if ( reLaunchVPN ){
111 | VpnManager manager = new VpnManager(InvisibleActivity.this);
112 | manager.connectVPN();
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import me.disconnect.mobile2.R;
4 | import me.disconnect.mobile.billing.BillingHelper;
5 | import me.disconnect.mobile.packages.PackageDescriptionManager;
6 | import me.disconnect.securefi.engine.VPNImplementation;
7 |
8 | import android.app.Activity;
9 | import android.app.Fragment;
10 | import android.content.Intent;
11 | import android.content.pm.PackageInfo;
12 | import android.content.pm.PackageManager.NameNotFoundException;
13 | import android.os.Bundle;
14 | import android.util.Log;
15 | import android.view.Menu;
16 | import android.view.MenuItem;
17 |
18 | public class MainActivity extends Activity {
19 | private static final String TAG = "MainActivity";
20 |
21 |
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_main);
27 |
28 | if (savedInstanceState == null) {
29 | getFragmentManager().beginTransaction()
30 | .add(R.id.container, new FrontScreenFragment()).commit();
31 | }
32 |
33 | // Get package information
34 | PackageDescriptionManager.getInstance().getDescriptionsAsync();
35 | }
36 |
37 | @Override
38 | public boolean onCreateOptionsMenu(Menu menu) {
39 |
40 | // Inflate the menu; this adds items to the action bar if it is present.
41 | getMenuInflater().inflate(R.menu.main, menu);
42 | return true;
43 | }
44 |
45 | @Override
46 | public boolean onOptionsItemSelected(MenuItem item) {
47 | // Handle action bar item clicks here. The action bar will
48 | // automatically handle clicks on the Home/Up button, so long
49 | // as you specify a parent activity in AndroidManifest.xml.
50 | int id = item.getItemId();
51 |
52 | switch ( id ){
53 | case R.id.about:{
54 | InfoActivity.show(this, R.string.about, R.string.about_page);
55 | break;
56 | }
57 | case R.id.privacy_policy:{
58 | InfoActivity.show(this, R.string.privacy_policy, R.string.privacy_page_text);
59 | break;
60 | }
61 | case R.id.basic_privacy_pack:{
62 | InfoActivity.show(this, R.string.basic_pack, R.string.basic_privacy_pack_text);
63 | break;
64 | }
65 | case R.id.advertising_filter_pack:{
66 | InfoActivity.show(this, R.string.ad_pack, R.string.advertising_pack_text);
67 | break;
68 | }
69 | case R.id.malware_protection_pack:{
70 | InfoActivity.show(this, R.string.malware_pack, R.string.malware_pack_text);
71 | break;
72 | }
73 | case R.id.send_feedback:{
74 | PackageInfo pinfo;
75 | String version = "0.0.0";
76 | try {
77 | pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
78 | version = pinfo.versionName;
79 | } catch (Exception e) {
80 | e.printStackTrace();
81 | }
82 | final Intent sendIntent = new Intent(Intent.ACTION_SEND);
83 | sendIntent.setType("plain/text");
84 | sendIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{DisconnectMobileConfig.FEEDBACK_EMAIL_ADDRESS});
85 | sendIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.feed_back_email_subject) + " - " + version);
86 | startActivity(Intent.createChooser(sendIntent, "Send mail..."));
87 | }
88 | }
89 |
90 | return super.onOptionsItemSelected(item);
91 | }
92 |
93 | // This is here only for when the user has been asked to approve this VPN app.
94 | // Calling connect again will succeed. It seems really wonky to require an Activity
95 | // simply to get the result of the system dialog, but Chiu-Ki says this is the right pattern.
96 | // Note: currently using InvisibleActivity for this so this version will not be called.
97 | @Override
98 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
99 | if(requestCode == VPNImplementation.PREPARE_VPN_SERVICE) {
100 | // if(resultCode == RESULT_OK)
101 | // ConnectivityReceiver.recheckConnection(this);
102 | // else // Forcing master switch. OK because user hit "Cancel".
103 | // getSharedPrefs().edit().putBoolean(SecureWireless.KEY_SECURE_ME, false).commit();
104 | } else if ( requestCode == BillingHelper.REQUEST_CODE || requestCode == 1337){
105 | Fragment fragment = (Fragment) getFragmentManager().findFragmentById(R.id.container);
106 | if(fragment != null){
107 | fragment.onActivityResult(requestCode, resultCode, data);
108 | }
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/PackageButton.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ToggleButton;
6 |
7 | public class PackageButton extends ToggleButton {
8 |
9 | public PackageButton(Context context, AttributeSet attrs, int defStyle) {
10 | super(context, attrs, defStyle);
11 | }
12 |
13 | public PackageButton(Context context, AttributeSet attrs) {
14 | super(context, attrs);
15 | }
16 |
17 | public PackageButton(Context context) {
18 | super(context);
19 | }
20 |
21 | public void toggle() {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/WebUpgradeActivity.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.SharedPreferences;
8 | import android.net.Uri;
9 | import android.os.AsyncTask;
10 | import android.os.Bundle;
11 | import android.view.Menu;
12 | import android.view.MenuInflater;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.webkit.WebSettings;
16 | import android.webkit.WebView;
17 | import android.webkit.WebViewClient;
18 | import android.widget.ProgressBar;
19 | import android.widget.Toast;
20 | import me.disconnect.mobile2.R;
21 |
22 | public class WebUpgradeActivity extends Activity {
23 |
24 | private WebView mWebView;
25 | private ProgressBar mLoadingSpinner;
26 | private boolean mClosing = false;
27 | private DisconnectMobilePrefs mPrefs;
28 |
29 | @SuppressLint("SetJavaScriptEnabled")
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.web_upgrade);
34 | getActionBar().setDisplayHomeAsUpEnabled(true); // Show the Up button in the action bar.
35 |
36 | // Get webview
37 | mWebView = (WebView) findViewById(R.id.webview);
38 | mLoadingSpinner = (ProgressBar)findViewById(R.id.loading_spinner);
39 |
40 | // Enable javascript
41 | WebSettings webSettings = mWebView.getSettings();
42 | webSettings.setJavaScriptEnabled(true);
43 |
44 | mWebView.setWebViewClient(new LocalWebViewClient());
45 |
46 | //Load preferences
47 | mPrefs = new DisconnectMobilePrefs(getApplicationContext());
48 |
49 | // Load upgrade page for user
50 | String url = "https://your-endpoint.com/upgrade";
51 |
52 | mWebView.loadUrl(url);
53 | }
54 |
55 | @Override
56 | public void onBackPressed() {
57 | if (mWebView.canGoBack()) {
58 | mWebView.goBack();
59 | return;
60 | }
61 |
62 | // Display progress spinner, and fetch updated status
63 | handleClose();
64 | }
65 |
66 | @Override
67 | public boolean onCreateOptionsMenu(Menu menu) {
68 | // Inflate the menu items for use in the action bar
69 | MenuInflater inflater = getMenuInflater();
70 | inflater.inflate(R.menu.web_upgrade_menu, menu);
71 | return super.onCreateOptionsMenu(menu);
72 | }
73 |
74 | @Override
75 | public boolean onOptionsItemSelected(MenuItem item) {
76 | switch (item.getItemId()) {
77 | // Respond to the action bar's Up/Home button
78 | case android.R.id.home:
79 | case R.id.action_close:
80 | handleClose();
81 | return true;
82 | }
83 | return super.onOptionsItemSelected(item);
84 | }
85 |
86 | // Display progress spinner, and fetches updated status
87 | private void handleClose(){
88 | if ( ! mClosing ){
89 | mClosing = true;
90 | }
91 | setResult(0, new Intent());
92 | finish();
93 | }
94 |
95 | private class LocalWebViewClient extends WebViewClient {
96 | @Override
97 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
98 | // TODO Add logic to decide if url should be loaded in the webview or not
99 | return false;
100 | // if (Uri.parse(url).getHost().equals("www.example.com")) {
101 | // // This the upgrade web site, so do not override; let the WebView load the page
102 | // return false;
103 | // }
104 | //
105 | // // Otherwise, launch another Activity that handles URLs
106 | // Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
107 | // startActivity(intent);
108 | // return true;
109 | }
110 |
111 | @Override
112 | public void onPageFinished(WebView view, String url) {
113 |
114 | if (url.equals("https://your-endpoint.com/purchased")) {
115 | mPrefs.setAdvertsPackagePurchased(true);
116 | mPrefs.setAdvertsPackage(true);
117 |
118 | //Payment successful
119 | setResult(1, new Intent());
120 |
121 | // Close webview after we're done
122 | finish();
123 | //mAdButton.setChecked(true);
124 | }
125 | super.onPageFinished(view, url);
126 |
127 | // Hide the loading spinner when the page has loaded
128 | mLoadingSpinner.setVisibility(View.GONE);
129 | }
130 | }
131 | }
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/Base64DecoderException.java:
--------------------------------------------------------------------------------
1 | // Copyright 2002, Google, Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package me.disconnect.mobile.billing;
16 |
17 | /**
18 | * Exception thrown when encountering an invalid Base64 input character.
19 | *
20 | * @author nelson
21 | */
22 | public class Base64DecoderException extends Exception {
23 | public Base64DecoderException() {
24 | super();
25 | }
26 |
27 | public Base64DecoderException(String s) {
28 | super(s);
29 | }
30 |
31 | private static final long serialVersionUID = 1L;
32 | }
33 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/BillingHelper.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.billing;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | import me.disconnect.securefi.engine.LoggingConfig;
7 |
8 | import android.app.Activity;
9 | import android.content.Context;
10 | import android.util.Log;
11 |
12 | public class BillingHelper extends IabHelper {
13 | private final static String TAG = "Billing Helper";
14 |
15 | // Request code for purchase flow
16 | public static final int REQUEST_CODE = 221163;
17 |
18 | // SKUs for purchases
19 | public static final String ADS_PACK_SKU = "malv_pack_180814";
20 | public static final String MALWARE_PACK_SKU = "malware_pack_180814";
21 |
22 | public static final List SKU_LIST = Arrays.asList(ADS_PACK_SKU, MALWARE_PACK_SKU );
23 |
24 | private Context mContext;
25 | // private IabHelper mHelper;
26 | private BillingObserver mBillingObserver;
27 |
28 | // License key for this app from the Services & APIs section of the Play listing,
29 | // broken into chunks and reassembled as suggested. Only reconstructed when needed.
30 | private static final String[] bits = {
31 | "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1rlEwbLcYPJRSM9fiN9JWl8FOtZlBfwaiMwUEvFfwC5rZc07J",
32 | "7xC422ApoI9/ByX4vYEjKWg6YkyqM75mLLbhIwPfQcDNrbHAb/aC4bUh2HEKUwoCUTOFFTWPS/OXkypvreDnUplq40scs6Y",
33 | "uPHUriCqKntx5hgz66JtcU+LOswIc8VPx+LdRcvjlxyJ0Wcp+qPdO1XOA0M7xZAyVko3R3pJ8a2USfh0pEv/DrsKk1kuMnVbL2N",
34 | "vpDs6S53El8WoSv7wISD9h6QW5RarFErFtBiEa5fUAkS6Ox+I8ty4htRkjdpshcJ81NMa25MF074J+wzneNXCW0WGLOfN5FvFQIDAQAB"
35 | };
36 |
37 |
38 | public BillingHelper(Context aContext, BillingObserver aBillingObserver) {
39 | super(aContext, "");
40 |
41 | mContext = aContext;
42 | mBillingObserver = aBillingObserver;
43 |
44 | // Construct base 64 Encoded public key with obscure variable name to help hide it.
45 | String BACKGROUND_IMAGE = "";
46 | for(String s : bits){
47 | BACKGROUND_IMAGE += s;
48 | }
49 |
50 | mSignatureBase64 = BACKGROUND_IMAGE;
51 |
52 | // enable debug logging (for a production application, you should set this to false).
53 | enableDebugLogging( LoggingConfig.LOGGING );
54 |
55 | // Start setup. This is asynchronous and the specified listener
56 | // will be called once setup completes.
57 | if ( LoggingConfig.LOGGING ){
58 | Log.d(TAG, "Starting setup.");
59 | }
60 | startSetup(mSetupListener);
61 | }
62 |
63 | private OnIabSetupFinishedListener mSetupListener = new IabHelper.OnIabSetupFinishedListener() {
64 | public void onIabSetupFinished(IabResult result) {
65 | Log.d(TAG, "Setup finished.");
66 |
67 | // Have we been disposed of in the meantime? If so, quit.
68 | if (mBillingObserver == null) {
69 | return;
70 | }
71 |
72 | // Report if subscription billing is available
73 | if ( result.isSuccess() ){
74 | mBillingObserver.billingAvailable(subscriptionsSupported());
75 | } else {
76 | mBillingObserver.billingAvailable(false);
77 | }
78 | }
79 | };
80 |
81 | // Release resources
82 | public void dispose(){
83 | super.dispose();
84 | mBillingObserver = null;
85 | }
86 |
87 | public void asyncGetInventory() {
88 | queryInventoryAsync(true, SKU_LIST, mGotInventoryListener);
89 | }
90 |
91 | private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
92 | public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
93 | if ( LoggingConfig.LOGGING ){
94 | Log.d(TAG, "Query inventory finished.");
95 | }
96 |
97 | // Have we been disposed of in the meantime? If so, quit.
98 | if (mBillingObserver == null) {
99 | return;
100 | }
101 |
102 | // Report if subscription billing is available
103 | if ( result.isSuccess() ){
104 | mBillingObserver.inventoryCompleted(inventory);
105 | } else {
106 | mBillingObserver.inventoryCompleted(null);
107 | }
108 |
109 |
110 | }
111 | };
112 |
113 | public void purchasePack(Activity aActivity, String sku) {
114 | // TODO what should the extra data be set to.
115 | String extraData = "";
116 | launchPurchaseFlow(aActivity, sku, REQUEST_CODE, mOnIabPurchaseFinishedListener, extraData);
117 | }
118 |
119 | private OnIabPurchaseFinishedListener mOnIabPurchaseFinishedListener = new OnIabPurchaseFinishedListener(){
120 |
121 | @Override
122 | public void onIabPurchaseFinished(IabResult result, Purchase aPurchaseInfo) {
123 | // Have we been disposed of in the meantime? If so, quit.
124 | if (mBillingObserver == null) {
125 | return;
126 | }
127 |
128 | if (result.isFailure()) {
129 | mBillingObserver.purchaseComplete(false);
130 | return;
131 | }
132 |
133 |
134 | mBillingObserver.purchaseComplete(true);
135 |
136 | // Purchase complete
137 | if ( LoggingConfig.LOGGING ){
138 | Log.d(TAG, "Purchase complete");
139 | }
140 |
141 | // TODO handle successful purchase
142 |
143 | }
144 | };
145 | }
146 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/BillingObserver.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.billing;
2 |
3 | public interface BillingObserver {
4 | public void billingAvailable(boolean aAvailable);
5 | public void inventoryCompleted(Inventory inventory);
6 | public void purchaseComplete(boolean aSuccess);
7 | }
8 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/IabException.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | /**
19 | * Exception thrown when something went wrong with in-app billing.
20 | * An IabException has an associated IabResult (an error).
21 | * To get the IAB result that caused this exception to be thrown,
22 | * call {@link #getResult()}.
23 | */
24 | public class IabException extends Exception {
25 | IabResult mResult;
26 |
27 | public IabException(IabResult r) {
28 | this(r, null);
29 | }
30 | public IabException(int response, String message) {
31 | this(new IabResult(response, message));
32 | }
33 | public IabException(IabResult r, Exception cause) {
34 | super(r.getMessage(), cause);
35 | mResult = r;
36 | }
37 | public IabException(int response, String message, Exception cause) {
38 | this(new IabResult(response, message), cause);
39 | }
40 |
41 | /** Returns the IAB result (error) that this exception signals. */
42 | public IabResult getResult() { return mResult; }
43 | }
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/IabResult.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | /**
19 | * Represents the result of an in-app billing operation.
20 | * A result is composed of a response code (an integer) and possibly a
21 | * message (String). You can get those by calling
22 | * {@link #getResponse} and {@link #getMessage()}, respectively. You
23 | * can also inquire whether a result is a success or a failure by
24 | * calling {@link #isSuccess()} and {@link #isFailure()}.
25 | */
26 | public class IabResult {
27 | int mResponse;
28 | String mMessage;
29 |
30 | public IabResult(int response, String message) {
31 | mResponse = response;
32 | if (message == null || message.trim().length() == 0) {
33 | mMessage = IabHelper.getResponseDesc(response);
34 | }
35 | else {
36 | mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")";
37 | }
38 | }
39 | public int getResponse() { return mResponse; }
40 | public String getMessage() { return mMessage; }
41 | public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; }
42 | public boolean isFailure() { return !isSuccess(); }
43 | public String toString() { return "IabResult: " + getMessage(); }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/Inventory.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * Represents a block of information about in-app items.
25 | * An Inventory is returned by such methods as {@link IabHelper#queryInventory}.
26 | */
27 | public class Inventory {
28 | Map mSkuMap = new HashMap();
29 | Map mPurchaseMap = new HashMap();
30 |
31 | Inventory() { }
32 |
33 | /** Returns the listing details for an in-app product. */
34 | public SkuDetails getSkuDetails(String sku) {
35 | return mSkuMap.get(sku);
36 | }
37 |
38 | /** Returns purchase information for a given product, or null if there is no purchase. */
39 | public Purchase getPurchase(String sku) {
40 | return mPurchaseMap.get(sku);
41 | }
42 |
43 | /** Returns whether or not there exists a purchase of the given product. */
44 | public boolean hasPurchase(String sku) {
45 | return mPurchaseMap.containsKey(sku);
46 | }
47 |
48 | /** Return whether or not details about the given product are available. */
49 | public boolean hasDetails(String sku) {
50 | return mSkuMap.containsKey(sku);
51 | }
52 |
53 | /**
54 | * Erase a purchase (locally) from the inventory, given its product ID. This just
55 | * modifies the Inventory object locally and has no effect on the server! This is
56 | * useful when you have an existing Inventory object which you know to be up to date,
57 | * and you have just consumed an item successfully, which means that erasing its
58 | * purchase data from the Inventory you already have is quicker than querying for
59 | * a new Inventory.
60 | */
61 | public void erasePurchase(String sku) {
62 | if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku);
63 | }
64 |
65 | /** Returns a list of all owned product IDs. */
66 | List getAllOwnedSkus() {
67 | return new ArrayList(mPurchaseMap.keySet());
68 | }
69 |
70 | /** Returns a list of all owned product IDs of a given type */
71 | List getAllOwnedSkus(String itemType) {
72 | List result = new ArrayList();
73 | for (Purchase p : mPurchaseMap.values()) {
74 | if (p.getItemType().equals(itemType)) result.add(p.getSku());
75 | }
76 | return result;
77 | }
78 |
79 | /** Returns a list of all purchases. */
80 | List getAllPurchases() {
81 | return new ArrayList(mPurchaseMap.values());
82 | }
83 |
84 | void addSkuDetails(SkuDetails d) {
85 | mSkuMap.put(d.getSku(), d);
86 | }
87 |
88 | void addPurchase(Purchase p) {
89 | mPurchaseMap.put(p.getSku(), p);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/Purchase.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | import org.json.JSONException;
19 | import org.json.JSONObject;
20 |
21 | /**
22 | * Represents an in-app billing purchase.
23 | */
24 | public class Purchase {
25 | public final static int PURCHASE_STATE_PURCHASED = 0;
26 |
27 | String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS
28 | String mOrderId;
29 | String mPackageName;
30 | String mSku;
31 | long mPurchaseTime;
32 | int mPurchaseState;
33 | String mDeveloperPayload;
34 | String mToken;
35 | String mOriginalJson;
36 | String mSignature;
37 |
38 | public Purchase(String itemType, String jsonPurchaseInfo, String signature) throws JSONException {
39 | mItemType = itemType;
40 | mOriginalJson = jsonPurchaseInfo;
41 | JSONObject o = new JSONObject(mOriginalJson);
42 | mOrderId = o.optString("orderId");
43 | mPackageName = o.optString("packageName");
44 | mSku = o.optString("productId");
45 | mPurchaseTime = o.optLong("purchaseTime");
46 | mPurchaseState = o.optInt("purchaseState");
47 | mDeveloperPayload = o.optString("developerPayload");
48 | mToken = o.optString("token", o.optString("purchaseToken"));
49 | mSignature = signature;
50 | }
51 |
52 | public String getItemType() { return mItemType; }
53 | public String getOrderId() { return mOrderId; }
54 | public String getPackageName() { return mPackageName; }
55 | public String getSku() { return mSku; }
56 | public long getPurchaseTime() { return mPurchaseTime; }
57 | public int getPurchaseState() { return mPurchaseState; }
58 | public String getDeveloperPayload() { return mDeveloperPayload; }
59 | public String getToken() { return mToken; }
60 | public String getOriginalJson() { return mOriginalJson; }
61 | public String getSignature() { return mSignature; }
62 |
63 | @Override
64 | public String toString() { return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; }
65 | }
66 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/Security.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | import android.text.TextUtils;
19 | import android.util.Log;
20 |
21 | import org.json.JSONException;
22 | import org.json.JSONObject;
23 |
24 |
25 | import java.security.InvalidKeyException;
26 | import java.security.KeyFactory;
27 | import java.security.NoSuchAlgorithmException;
28 | import java.security.PublicKey;
29 | import java.security.Signature;
30 | import java.security.SignatureException;
31 | import java.security.spec.InvalidKeySpecException;
32 | import java.security.spec.X509EncodedKeySpec;
33 |
34 | /**
35 | * Security-related methods. For a secure implementation, all of this code
36 | * should be implemented on a server that communicates with the
37 | * application on the device. For the sake of simplicity and clarity of this
38 | * example, this code is included here and is executed on the device. If you
39 | * must verify the purchases on the phone, you should obfuscate this code to
40 | * make it harder for an attacker to replace the code with stubs that treat all
41 | * purchases as verified.
42 | */
43 | public class Security {
44 | private static final String TAG = "IABUtil/Security";
45 |
46 | private static final String KEY_FACTORY_ALGORITHM = "RSA";
47 | private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
48 |
49 | /**
50 | * Verifies that the data was signed with the given signature, and returns
51 | * the verified purchase. The data is in JSON format and signed
52 | * with a private key. The data also contains the {@link PurchaseState}
53 | * and product ID of the purchase.
54 | * @param base64PublicKey the base64-encoded public key to use for verifying.
55 | * @param signedData the signed JSON string (signed, not encrypted)
56 | * @param signature the signature for the data, signed with the private key
57 | */
58 | public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
59 | if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
60 | TextUtils.isEmpty(signature)) {
61 | Log.e(TAG, "Purchase verification failed: missing data.");
62 | return false;
63 | }
64 |
65 | PublicKey key = Security.generatePublicKey(base64PublicKey);
66 | return Security.verify(key, signedData, signature);
67 | }
68 |
69 | /**
70 | * Generates a PublicKey instance from a string containing the
71 | * Base64-encoded public key.
72 | *
73 | * @param encodedPublicKey Base64-encoded public key
74 | * @throws IllegalArgumentException if encodedPublicKey is invalid
75 | */
76 | public static PublicKey generatePublicKey(String encodedPublicKey) {
77 | try {
78 | byte[] decodedKey = Base64.decode(encodedPublicKey);
79 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
80 | return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
81 | } catch (NoSuchAlgorithmException e) {
82 | throw new RuntimeException(e);
83 | } catch (InvalidKeySpecException e) {
84 | Log.e(TAG, "Invalid key specification.");
85 | throw new IllegalArgumentException(e);
86 | } catch (Base64DecoderException e) {
87 | Log.e(TAG, "Base64 decoding failed.");
88 | throw new IllegalArgumentException(e);
89 | }
90 | }
91 |
92 | /**
93 | * Verifies that the signature from the server matches the computed
94 | * signature on the data. Returns true if the data is correctly signed.
95 | *
96 | * @param publicKey public key associated with the developer account
97 | * @param signedData signed data from server
98 | * @param signature server signature
99 | * @return true if the data and signature match
100 | */
101 | public static boolean verify(PublicKey publicKey, String signedData, String signature) {
102 | Signature sig;
103 | try {
104 | sig = Signature.getInstance(SIGNATURE_ALGORITHM);
105 | sig.initVerify(publicKey);
106 | sig.update(signedData.getBytes());
107 | if (!sig.verify(Base64.decode(signature))) {
108 | Log.e(TAG, "Signature verification failed.");
109 | return false;
110 | }
111 | return true;
112 | } catch (NoSuchAlgorithmException e) {
113 | Log.e(TAG, "NoSuchAlgorithmException.");
114 | } catch (InvalidKeyException e) {
115 | Log.e(TAG, "Invalid key specification.");
116 | } catch (SignatureException e) {
117 | Log.e(TAG, "Signature exception.");
118 | } catch (Base64DecoderException e) {
119 | Log.e(TAG, "Base64 decoding failed.");
120 | } catch (RuntimeException e) {
121 | Log.e(TAG, "RuntimeException in Security.verify():");
122 | e.printStackTrace();
123 | }
124 | return false;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/billing/SkuDetails.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package me.disconnect.mobile.billing;
17 |
18 | import org.json.JSONException;
19 | import org.json.JSONObject;
20 |
21 | /**
22 | * Represents an in-app product's listing details.
23 | */
24 | public class SkuDetails {
25 | String mItemType;
26 | String mSku;
27 | String mType;
28 | String mPrice;
29 | String mTitle;
30 | String mDescription;
31 | String mJson;
32 |
33 | public SkuDetails(String jsonSkuDetails) throws JSONException {
34 | this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
35 | }
36 |
37 | public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
38 | mItemType = itemType;
39 | mJson = jsonSkuDetails;
40 | JSONObject o = new JSONObject(mJson);
41 | mSku = o.optString("productId");
42 | mType = o.optString("type");
43 | mPrice = o.optString("price");
44 | mTitle = o.optString("title");
45 | mDescription = o.optString("description");
46 | }
47 |
48 | public String getSku() { return mSku; }
49 | public String getType() { return mType; }
50 | public String getPrice() { return mPrice; }
51 | public String getTitle() { return mTitle; }
52 | public String getDescription() { return mDescription; }
53 |
54 | @Override
55 | public String toString() {
56 | return "SkuDetails:" + mJson;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/packages/PackageAlertDialog.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.packages;
2 |
3 | import me.disconnect.mobile2.R;
4 | import me.disconnect.mobile.packages.PackageAlertDialog.PackageAlertDialogListener;
5 | import android.app.AlertDialog;
6 | import android.app.Dialog;
7 | import android.app.DialogFragment;
8 | import android.app.NotificationManager;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.SharedPreferences;
12 | import android.os.Bundle;
13 | import android.view.ContextThemeWrapper;
14 | import android.view.View;
15 | import android.view.View.OnClickListener;
16 | import android.widget.Button;
17 | import android.widget.ImageView;
18 | import android.widget.TextView;
19 |
20 | public class PackageAlertDialog extends DialogFragment {
21 |
22 | private static final String PACKAGE_ID = "package_id";
23 | private static final String ACTIVATED = "activated";
24 | private static final String PURCHASED = "purchased";
25 | private static final String ICON_RES_ID = "icon_id";
26 | private static final String PACKAGE_PRICE = "price";
27 |
28 | public interface PackageAlertDialogListener {
29 | public void activatePressed(int aPackageId, boolean aActivate);
30 | public void purchasePressed(final int aPackageId, final int nativeBilling);
31 | }
32 |
33 | public static PackageAlertDialog newInstance(int aPackageId, boolean isActivated, boolean isPurchased,
34 | int aIconResId, String aPrice) {
35 | PackageAlertDialog frag = new PackageAlertDialog();
36 |
37 | Bundle args = new Bundle();
38 | args.putInt(PACKAGE_ID, aPackageId);
39 | args.putBoolean(ACTIVATED, isActivated);
40 | args.putBoolean(PURCHASED, isPurchased);
41 | args.putInt(ICON_RES_ID, aIconResId );
42 | args.putString(PACKAGE_PRICE, aPrice);
43 | frag.setArguments(args);
44 |
45 | return frag;
46 | }
47 |
48 | private PackageAlertDialogListener mListener;
49 |
50 | public void setListener(PackageAlertDialogListener aListener){
51 | mListener = aListener;
52 | }
53 |
54 | @Override
55 | public Dialog onCreateDialog(Bundle savedInstanceState) {
56 | final int packageId = getArguments().getInt(PACKAGE_ID, 0);
57 | PackageDescription packDesc = PackageDescriptionManager.getInstance().getPackageDescription(packageId);
58 |
59 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
60 |
61 | View view = getActivity().getLayoutInflater().inflate(R.layout.package_alert_dialog, null);
62 | alertDialogBuilder.setView(view);
63 |
64 | setText(view, R.id.title, packDesc.mPackTitle);
65 | setText(view, R.id.main_text, packDesc.mMainText);
66 | setText(view, R.id.footer, packDesc.mFooter);
67 |
68 | // Set icon
69 | int iconResId = getArguments().getInt(ICON_RES_ID, 0);
70 | ImageView icon = (ImageView) view.findViewById(R.id.package_icon);
71 | icon.setImageResource(iconResId);
72 |
73 | final boolean isPurchased = getArguments().getBoolean(PURCHASED, false);
74 | Button activateButton = (Button)view.findViewById(R.id.activate_button);
75 | final boolean isActivated = getArguments().getBoolean(ACTIVATED, false);
76 | if ( isPurchased ) {
77 | if ( isActivated ){
78 | activateButton.setText(R.string.package_alert_dialog_deactivate);
79 | }
80 | } else {
81 | // Set purchase price
82 | String price = getArguments().getString(PACKAGE_PRICE);
83 | activateButton.setText(price);
84 | }
85 |
86 | // Set whether or not we should use Google Play or Stripe
87 | final int nativeBilling = packDesc.mUseNativeBilling;
88 |
89 | activateButton.setOnClickListener(new OnClickListener(){
90 | @Override
91 | public void onClick(View v) {
92 |
93 | if ( isPurchased ){
94 | mListener.activatePressed(packageId, !isActivated);
95 | } else {
96 | mListener.purchasePressed(packageId, nativeBilling);
97 | }
98 | dismiss();
99 | }
100 | });
101 |
102 | Button cancelButton = (Button)view.findViewById(R.id.cancel_button);
103 | cancelButton.setOnClickListener(new OnClickListener(){
104 | @Override
105 | public void onClick(View v) {
106 | dismiss();
107 | }
108 | });
109 |
110 | return alertDialogBuilder.create();
111 | }
112 |
113 | private void setText(View view, int resId, String text) {
114 | TextView textView = (TextView)view.findViewById(resId);
115 | textView.setText(text);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/packages/PackageDescription.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.packages;
2 |
3 | public class PackageDescription {
4 | public String mBlockTestDomain;
5 | public long mLastUpdate;
6 | public String mName;
7 | public String mFooter;
8 | public String mPackTitle;
9 | public String mHomeScreenTitle;
10 | public String mSubTitle;
11 | public int mId;
12 | public String mMainText;
13 | public int mUseNativeBilling;
14 | }
15 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/packages/PackageDescriptionManager.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.packages;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import android.util.SparseArray;
8 |
9 | import me.disconnect.mobile.DisconnectMobileConfig;
10 | import me.disconnect.mobile.packages.Provisioner.PackagesResultProcessor;
11 |
12 | public class PackageDescriptionManager implements PackagesResultProcessor{
13 | private static PackageDescriptionManager mInstance;
14 | private SparseArray mPackages = new SparseArray();
15 |
16 | public static PackageDescriptionManager getInstance(){
17 | if ( mInstance == null ){
18 | mInstance = new PackageDescriptionManager();
19 | }
20 |
21 | return mInstance;
22 | }
23 |
24 | public void getDescriptionsAsync(){
25 | Provisioner.refreshPackages(
26 | this
27 | , DisconnectMobileConfig.PACKAGE_PROVISIONING_URL
28 | );
29 | }
30 |
31 | @Override
32 | public void processResult(JSONArray result) {
33 | int numPackages = result.length();
34 | for (int index = 0; index < numPackages; index++ ){
35 | try {
36 | PackageDescription packDesc = new PackageDescription();
37 | JSONObject jsonObject = result.getJSONObject(index);
38 | packDesc.mBlockTestDomain = jsonObject.getString("block_test_domain");
39 | packDesc.mFooter = jsonObject.getString("footer");
40 | packDesc.mHomeScreenTitle = jsonObject.getString("home_screen_title");
41 | packDesc.mId = jsonObject.getInt("id");
42 | packDesc.mLastUpdate = jsonObject.optLong("last_updated");
43 | packDesc.mMainText = jsonObject.getString("main_text");
44 | packDesc.mName = jsonObject.getString("name");
45 | packDesc.mPackTitle = jsonObject.getString("pack_title");
46 | packDesc.mSubTitle = jsonObject.getString("subtitle");
47 | packDesc.mUseNativeBilling = jsonObject.getInt("native_billing");
48 | mPackages.put(packDesc.mId, packDesc);
49 | } catch (JSONException exception){
50 | exception.printStackTrace();
51 | }
52 | }
53 | }
54 |
55 | @Override
56 | public void onError() {
57 | // TODO handle error
58 | }
59 |
60 | public PackageDescription getPackageDescription(int aPackageId){
61 | return mPackages.get(aPackageId);
62 | }
63 |
64 | public boolean downloadComplete(){
65 | return mPackages.size() > 0;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/packages/Provisioner.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.packages;
2 |
3 | import android.os.AsyncTask;
4 | import android.util.Log;
5 |
6 | import org.apache.http.HttpEntity;
7 | import org.apache.http.HttpResponse;
8 | import org.apache.http.NameValuePair;
9 | import org.apache.http.StatusLine;
10 | import org.apache.http.client.ClientProtocolException;
11 | import org.apache.http.client.HttpClient;
12 | import org.apache.http.client.entity.UrlEncodedFormEntity;
13 | import org.apache.http.client.methods.HttpGet;
14 | import org.apache.http.client.methods.HttpPost;
15 | import org.apache.http.impl.client.DefaultHttpClient;
16 | import org.apache.http.message.BasicNameValuePair;
17 | import org.json.JSONArray;
18 | import org.json.JSONException;
19 | import org.json.JSONObject;
20 |
21 | import java.io.BufferedReader;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.io.InputStreamReader;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * Utility for getting package information from back end.
30 | */
31 | public class Provisioner{
32 |
33 | public interface PackagesResultProcessor {
34 | /**
35 | * @param result a JSON array
36 | */
37 | public void processResult(JSONArray result);
38 | public void onError();
39 | }
40 |
41 | /**
42 | * High-level utility to refresh packages back-end status.
43 | * Hits the with a given url
44 | * Call from the UI thread. Runs asynchronously. Results returned on UI thread.
45 | * @param processor Callback object to read from the JSON results.
46 | * @param urlAndNameValuePairs Provisioning or status URL
47 | */
48 | public static void refreshPackages(final PackagesResultProcessor processor, String url) {
49 | new AsyncTask() {
50 | @Override
51 | protected JSONArray doInBackground(String... params) {
52 | return refresh(params);
53 | }
54 | @Override
55 | protected void onPostExecute(JSONArray result) {
56 | if(result != null){
57 | processor.processResult(result);
58 | } else {
59 | processor.onError();
60 | }
61 | }
62 | }.execute(url);
63 | }
64 |
65 | /**
66 | * Low-level workhorse method. Runs synchronously.
67 | */
68 | public static JSONArray refresh(String... params) {
69 | String url = params[0];
70 | HttpClient httpclient = new DefaultHttpClient();
71 | // Post arguments include "amount" - integer number of megabytes desired for the account for debugging.
72 | HttpGet httpget = new HttpGet(url);
73 | try {
74 | // Execute HTTP Post Request
75 | HttpResponse response = httpclient.execute(httpget);
76 | StatusLine statusLine = response.getStatusLine();
77 | int statusCode = statusLine.getStatusCode();
78 | if (statusCode != 200) {
79 | // Log.e(SecureWireless.LOG_TAG, "Status refresh failed with status code " + statusCode);
80 | return null;
81 | }
82 | HttpEntity entity = response.getEntity();
83 | InputStream inputStream = entity.getContent();
84 | // json is UTF-8 by default
85 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
86 | StringBuilder sb = new StringBuilder();
87 | String line = null;
88 | while ((line = reader.readLine()) != null)
89 | sb.append(line + "\n");
90 | try {
91 | return new JSONArray(sb.toString());
92 | } catch (JSONException e) {
93 | e.printStackTrace();
94 | }
95 | } catch (ClientProtocolException e) {
96 | e.printStackTrace();
97 | } catch (IOException e) {
98 | e.printStackTrace();
99 | }
100 | return null;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/vpn/SecureFiDetector.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.vpn;
2 |
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 |
6 | import me.disconnect.mobile.DisconnectMobileConfig;
7 |
8 | import android.content.Context;
9 | import android.content.pm.PackageInfo;
10 | import android.content.pm.PackageManager.NameNotFoundException;
11 | import android.os.AsyncTask;
12 |
13 | /*
14 | * Detects if the securefi app is installed, and if it's VPN
15 | * is currently connected.
16 | */
17 | public class SecureFiDetector extends AsyncTask {
18 | public interface SecureFiObserver {
19 | void secureFiActive(Boolean aIsActive);
20 | }
21 |
22 | public static void discoverIfActiveAsync(Context aContext, SecureFiObserver aObserver){
23 | SecureFiDetector detector = new SecureFiDetector(aContext, aObserver);
24 | detector.execute();
25 | }
26 |
27 | private Context mContext;
28 | private SecureFiObserver mObserver;
29 |
30 | private SecureFiDetector(Context aContext, SecureFiObserver aObserver) {
31 | mContext = aContext;
32 | mObserver = aObserver;
33 | }
34 |
35 | @Override
36 | protected Boolean doInBackground(Void... params) {
37 | if ( !isInstalled() ){
38 | return false;
39 | }
40 |
41 | String dnsForHost = getDNSForHostName(DisconnectMobileConfig.HOST_NAME);
42 |
43 | return dnsForHost != null && dnsForHost.equals(DisconnectMobileConfig.IP_ADDRESS_IF_BLOCKED);
44 | }
45 |
46 | @Override
47 | protected void onPostExecute(Boolean result) {
48 | super.onPostExecute(result);
49 | mObserver.secureFiActive(result);
50 | }
51 |
52 | private String getDNSForHostName(String aHostName){
53 | InetAddress address = null;
54 | try {
55 | address = InetAddress.getByName(aHostName);
56 | } catch (UnknownHostException e) {
57 | // Couldn't find host name
58 | address = null;
59 | }
60 |
61 | return address == null ? null : address.getHostAddress();
62 | }
63 |
64 | private boolean isInstalled() {
65 | android.content.pm.PackageManager mPm = mContext.getPackageManager();
66 | PackageInfo info;
67 | try {
68 | info = mPm.getPackageInfo(DisconnectMobileConfig.ALTERNATIVE_APP_PACKAGE_NAME, 0);
69 | } catch (NameNotFoundException e) {
70 | // if not found
71 | info = null;
72 | }
73 |
74 | boolean installed = (info != null);
75 | return installed;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/vpn/SynchronizedFactory.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.vpn;
2 |
3 | import java.lang.reflect.InvocationHandler;
4 | import java.lang.reflect.Method;
5 | import java.lang.reflect.Proxy;
6 |
7 | /**
8 | * Factory class capable of producing synchronized wrapper for arbitrary objects.
9 | * From http://stackoverflow.com/questions/743288/java-synchronization-utility
10 | * @author Chris Jester-Young, http://about.me/cky
11 | */
12 | public final class SynchronizedFactory {
13 | private SynchronizedFactory() {} // Private constructor guarantees no instances get created.
14 |
15 | /**
16 | * Utility that can take any object that implements a given interface and returns
17 | * a proxy that implements the same interface and synchronizes all calls that are
18 | * delegated to the given object. From Chris Jester-Young, http://about.me/cky
19 | * @param interfaceClass The interface to synchronize. Use MyInterface.class.
20 | * @param object The object to synchronize that implements the given interface class.
21 | * @return A synchronized proxy object that delegates to the given object.
22 | */
23 | public static T makeSynchronized(Class interfaceClass, final T object) {
24 | return interfaceClass.cast(
25 | Proxy.newProxyInstance(
26 | object.getClass().getClassLoader(),
27 | new Class>[]{interfaceClass},
28 | new InvocationHandler() {
29 | @Override
30 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
31 | synchronized (object) {
32 | return method.invoke(object, args);
33 | }
34 | }
35 | }
36 | )
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/vpn/VPNProvider.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.vpn;
2 |
3 | import me.disconnect.securefi.engine.VPNImplementation;
4 | import me.disconnect.securefi.openvpnlib.OpenVPNImplementation;
5 |
6 | import android.content.Context;
7 |
8 | /**
9 | * Singleton source of current VPN provider implementation.
10 | * Change this code when you want to switch providers for testing or porting.
11 | * We could also support run-time switching via a SharedPreference provider name, etc.
12 | */
13 | public class VPNProvider {
14 | private static VPNImplementation mProvider;
15 |
16 | private VPNProvider(){} // Empty private constructor guarantees no instances get created.
17 |
18 | public static VPNImplementation getInstance(Context aContext) {
19 | // Rather than return mProvider as typical, I'm wrapping it in a proxy object
20 | // that delegates all interface calls that synchronize on the instance.
21 | if ( mProvider == null ){
22 | mProvider = new OpenVPNImplementation(aContext);
23 | }
24 |
25 | return SynchronizedFactory.makeSynchronized(VPNImplementation.class, mProvider);
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/disconnect/src/me/disconnect/mobile/vpn/VpnManager.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.mobile.vpn;
2 |
3 | import java.math.BigInteger;
4 | import java.security.SecureRandom;
5 |
6 | import me.disconnect.mobile.DisconnectMobileConfig;
7 | import me.disconnect.mobile.DisconnectMobilePrefs;
8 | import me.disconnect.mobile2.R;
9 | import me.disconnect.securefi.engine.VPNImplementation;
10 | import android.content.Context;
11 | import android.util.SparseIntArray;
12 |
13 | public class VpnManager {
14 | private static SecureRandom mSecureRandom = new SecureRandom();
15 | private Context mContext;
16 | private VPNImplementation mVPNImplementation;
17 | private DisconnectMobilePrefs mPrefs;
18 |
19 | private final static SparseIntArray mPortMap = new SparseIntArray() {
20 | {
21 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED, 80 );
22 | append( DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, 1190 );
23 | append( DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED, 1254 );
24 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, 1192 );
25 | append( DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, 1191 );
26 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED, 1196 );
27 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, 443 );
28 | }
29 | };
30 |
31 | private final static SparseIntArray mMessageMap = new SparseIntArray() {
32 | {
33 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED, R.string.vpn_connected_basic );
34 | append( DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, R.string.vpn_connected_ads );
35 | append( DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED, R.string.vpn_connected_malware );
36 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, R.string.vpn_connected_basic_ads );
37 | append( DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, R.string.vpn_connected_ads_malware);
38 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED, R.string.vpn_connected_basic_malware);
39 | append( DisconnectMobilePrefs.BASIC_PACKAGE_ACTIVATED | DisconnectMobilePrefs.MALWARE_PACKAGE_ACTIVATED | DisconnectMobilePrefs.ADS_PACKAGE_ACTIVATED, R.string.vpn_connected_basic_ads_malware );
40 | }
41 | };
42 |
43 |
44 | public VpnManager(Context aContext){
45 | mContext = aContext;
46 | mVPNImplementation = VPNProvider.getInstance(aContext);
47 | mPrefs = new DisconnectMobilePrefs(aContext);
48 | }
49 |
50 | public void connectVPN(){
51 | // Set connected message
52 | setProtectedMessage();
53 |
54 | // Use your username logic here - randomized for example
55 | String username = mPrefs.generatedUsername();
56 | if(username == null){
57 | username = generateRandomString();
58 | mPrefs.setGeneratedUsername(username);
59 | }
60 |
61 | // This generates a random password - insert your password here
62 | String password = generateRandomString();
63 |
64 | String crtCert = mContext.getString(R.string.ca_cert);
65 | String taCert = mContext.getString(R.string.ta_cert);
66 | String clientCert = mContext.getString(R.string.client_cert);
67 | String genericClientKey = mContext.getString(R.string.non_priv_key);
68 | String configFile = mContext.getString(R.string.config_file);
69 | String gateway = DisconnectMobileConfig.SERVER_GATEWAY;
70 | int[] ports = findPortForPackages();
71 |
72 | mVPNImplementation.connect(username, password, gateway, ports, crtCert, taCert, clientCert, genericClientKey, configFile);
73 | }
74 |
75 | private int[] findPortForPackages() {
76 | int packageBitFlags = mPrefs.getAvailablePackages();
77 | return new int[]{mPortMap.get(packageBitFlags)};
78 | }
79 |
80 | private String generateRandomString() {
81 | return new BigInteger(130, mSecureRandom).toString(32);
82 | }
83 |
84 | private void setProtectedMessage(){
85 | int packageBitFlags = mPrefs.getAvailablePackages();
86 | int resourceId = mMessageMap.get(packageBitFlags);
87 | String connectedMessage = mContext.getString(resourceId);
88 | mPrefs.setProtectedMessage(connectedMessage);
89 | }
90 |
91 |
92 | public void disconnectVPN(){
93 | mVPNImplementation.disconnect();
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/engineinterface/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/engineinterface/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | EngineInterface
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/engineinterface/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/engineinterface/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/engineinterface/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/engineinterface/config/LoggingConfig.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.securefi.engine;
2 |
3 | /** WARNING
4 | *
5 | * This file is automatically updated using ANT to config either
6 | * the BlackPhone or Google Billing builds. Any changes should be made to
7 | * the version in /config rather than in /src/me/disconnect/securefi/engine
8 | */
9 |
10 | public class LoggingConfig {
11 | /** Black phone or Google billing build **/
12 | public final static boolean LOGGING = @CONFIG.LOGGING@;
13 | }
14 |
--------------------------------------------------------------------------------
/engineinterface/custom_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/engineinterface/custom_rules.xml~:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/engineinterface/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/engineinterface/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/engineinterface/src/me/disconnect/securefi/engine/LoggingConfig.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.securefi.engine;
2 |
3 | /** WARNING
4 | *
5 | * This file is automatically updated using ANT to config either
6 | * the logging on or off Any changes should be made to
7 | * the version in /config rather than in /src/me/disconnect/securefi/engine
8 | */
9 |
10 | public class LoggingConfig {
11 | public final static boolean LOGGING = true;
12 | }
13 |
--------------------------------------------------------------------------------
/engineinterface/src/me/disconnect/securefi/engine/VPNImplementation.java:
--------------------------------------------------------------------------------
1 | package me.disconnect.securefi.engine;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Contract for supported VPN implementations.
7 | */
8 | public interface VPNImplementation {
9 | public final int PREPARE_VPN_SERVICE = 213;
10 |
11 | public static final String LAUNCH_THIS = "launch this";
12 |
13 | // Shared Preferences
14 | public static final String KEY_BANDWIDTH_LIMIT = "bandwidth limit"; // In megabytes
15 | public static final String KEY_BANDWIDTH_USED = "bandwidth used"; // In megabytes
16 | public static final String VPN_PREFS = "vpn preferences"; // SharedPreferences file name.
17 | public static final String KEY_GETTING_PERMISSION = "getting permission"; // semaphore to serialize the approval process.
18 | public static final String KEY_PERMISSION_REVOKED = "permission revoked"; // If user wants us all the way off.
19 | public static final String PROTECTED_MESSAGE = "VPN_CONNECTED_MESSAGE"; // Message to show when vpn is connected.
20 |
21 | // default values
22 | public static final float DEFAULT_BANDWIDTH_LIMIT = 10;
23 | // Identifies our status notification so we can update it. Can be any integer we like.
24 | public static final int NOTIFICATION_ID = 415;
25 |
26 | /**
27 | * Connection states and support for listeners to state changes.
28 | */
29 | public enum CONNECTION_STATE { DISABLED, CONNECTING, CONNECTED, DISCONNECTING }
30 | public interface ConnectionListener {
31 | public void stateChanged(CONNECTION_STATE newState);
32 | }
33 | public void addStateListener(ConnectionListener sl);
34 | public void removeStateListener(ConnectionListener sl);
35 | public void fireStateChanged(); // Normally protected method.
36 | public CONNECTION_STATE getConnectionState();
37 |
38 | /**
39 | * Attempts to connect to start the VPN service.
40 | * This requires the user to approve this action, at least initially.
41 | * For new connections the user will be presented with a system dialog.
42 | * When the user agrees, the given Activity's onActivityResult() method is called,
43 | * and will be passed the above PREPARE_VPN_SERVICE request code.
44 | * Assuming the result code is RESULT_OK, the onActivityResult() method
45 | * must call connect() once more to complete the connection.
46 | */
47 | public void connect(String username, String password, String aGateway, int[] aPorts, String aCrtCert, String aTaCert, String aClientCert, String aClientKey, String aConfigFile);
48 | public void disconnect();
49 |
50 | /*
51 | * Called when the connectivity receiver detects that the network has changed. It
52 | * is the responsibility of the provider to manage the transition to the new
53 | * network.
54 | */
55 | public void networkChanged();
56 |
57 | /**
58 | * Stops VPN provider. Stops any background servicers started by provider
59 | * and deregisters any observers.
60 | */
61 | public void stopProvider();
62 |
63 | // TODO Implement proper message handling back to UX
64 | public void init(Context context);
65 | public void endit(Context context);
66 | }
67 |
--------------------------------------------------------------------------------