diff options
author | Fil <fil.bergamo@riseup.net> | 2017-12-17 12:59:08 +0100 |
---|---|---|
committer | Fil <fil.bergamo@riseup.net> | 2017-12-17 13:32:16 +0100 |
commit | bf2cc09307e404a8d6de0bfd77e1e8366e1a0497 (patch) | |
tree | a402e530fbba54a1a50c3fae5ef63a8c33204a5c /app | |
parent | 4a005f9be829b18438f5343d5104c840efd36ea5 (diff) | |
download | RepWifiApp-0.6.tar.gz RepWifiApp-0.6.tar.bz2 RepWifiApp-0.6.zip |
new version v0.6 - new features plus code cleanupv0.6
* NEW: introduced static IP/gateway settings per network.
* NEW: added OpenVPN support via interaction with de.blinkt.openvpn
* completed french translation by Nicola Spanti.
* improved stability by changing dhcpcd options.
* better shell command handling, with direct output reading.
* better network storage, based on JSON instead of TSV.
* cleaned up engine's code.
* clean up xml styling files
* replaced all string litterals with @string resoruces
Diffstat (limited to 'app')
55 files changed, 3807 insertions, 1119 deletions
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index 891cca9..c20db8a 100644 --- a/app/AndroidManifest.xml +++ b/app/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fil.libre.repwifiapp" - android:versionCode="3" - android:versionName="0.5" > + android:versionCode="4" + android:versionName="0.6" > <uses-sdk android:minSdkVersion="17" @@ -48,7 +48,7 @@ <activity android:name="fil.libre.repwifiapp.activities.MainActivity" android:label="@string/app_name" - android:launchMode="singleTop" + android:launchMode="singleTop" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -87,6 +87,15 @@ android:name="fil.libre.repwifiapp.activities.InputSsidActivity" android:label="@string/title_activity_input_ssid" > </activity> + <activity + android:name="fil.libre.repwifiapp.activities.Ipv4SettingsActivity" + android:label="@string/title_activity_ipv4_settings" > + </activity> + <activity + android:name="fil.libre.repwifiapp.activities.VpnSettingsActivity" + android:label="@string/title_activity_vpn_settings" > + </activity> + <service android:name="de.blinkt.openvpn.api.IOpenVPNAPIService"></service> </application> </manifest>
\ No newline at end of file diff --git a/app/gen/de/blinkt/openvpn/api/IOpenVPNAPIService.java b/app/gen/de/blinkt/openvpn/api/IOpenVPNAPIService.java new file mode 100644 index 0000000..7f11034 --- /dev/null +++ b/app/gen/de/blinkt/openvpn/api/IOpenVPNAPIService.java @@ -0,0 +1,545 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + * Original file: /home/fil/workspace/RepWifiApp/src/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl + */ +package de.blinkt.openvpn.api; +public interface IOpenVPNAPIService extends android.os.IInterface +{ +/** Local-side IPC implementation stub class. */ +public static abstract class Stub extends android.os.Binder implements de.blinkt.openvpn.api.IOpenVPNAPIService +{ +private static final java.lang.String DESCRIPTOR = "de.blinkt.openvpn.api.IOpenVPNAPIService"; +/** Construct the stub at attach it to the interface. */ +public Stub() +{ +this.attachInterface(this, DESCRIPTOR); +} +/** + * Cast an IBinder object into an de.blinkt.openvpn.api.IOpenVPNAPIService interface, + * generating a proxy if needed. + */ +public static de.blinkt.openvpn.api.IOpenVPNAPIService asInterface(android.os.IBinder obj) +{ +if ((obj==null)) { +return null; +} +android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); +if (((iin!=null)&&(iin instanceof de.blinkt.openvpn.api.IOpenVPNAPIService))) { +return ((de.blinkt.openvpn.api.IOpenVPNAPIService)iin); +} +return new de.blinkt.openvpn.api.IOpenVPNAPIService.Stub.Proxy(obj); +} +@Override public android.os.IBinder asBinder() +{ +return this; +} +@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException +{ +switch (code) +{ +case INTERFACE_TRANSACTION: +{ +reply.writeString(DESCRIPTOR); +return true; +} +case TRANSACTION_getProfiles: +{ +data.enforceInterface(DESCRIPTOR); +java.util.List<de.blinkt.openvpn.api.APIVpnProfile> _result = this.getProfiles(); +reply.writeNoException(); +reply.writeTypedList(_result); +return true; +} +case TRANSACTION_startProfile: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +this.startProfile(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_addVPNProfile: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +java.lang.String _arg1; +_arg1 = data.readString(); +boolean _result = this.addVPNProfile(_arg0, _arg1); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_startVPN: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +this.startVPN(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_prepare: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +android.content.Intent _result = this.prepare(_arg0); +reply.writeNoException(); +if ((_result!=null)) { +reply.writeInt(1); +_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +} +else { +reply.writeInt(0); +} +return true; +} +case TRANSACTION_prepareVPNService: +{ +data.enforceInterface(DESCRIPTOR); +android.content.Intent _result = this.prepareVPNService(); +reply.writeNoException(); +if ((_result!=null)) { +reply.writeInt(1); +_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +} +else { +reply.writeInt(0); +} +return true; +} +case TRANSACTION_disconnect: +{ +data.enforceInterface(DESCRIPTOR); +this.disconnect(); +reply.writeNoException(); +return true; +} +case TRANSACTION_pause: +{ +data.enforceInterface(DESCRIPTOR); +this.pause(); +reply.writeNoException(); +return true; +} +case TRANSACTION_resume: +{ +data.enforceInterface(DESCRIPTOR); +this.resume(); +reply.writeNoException(); +return true; +} +case TRANSACTION_registerStatusCallback: +{ +data.enforceInterface(DESCRIPTOR); +de.blinkt.openvpn.api.IOpenVPNStatusCallback _arg0; +_arg0 = de.blinkt.openvpn.api.IOpenVPNStatusCallback.Stub.asInterface(data.readStrongBinder()); +this.registerStatusCallback(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_unregisterStatusCallback: +{ +data.enforceInterface(DESCRIPTOR); +de.blinkt.openvpn.api.IOpenVPNStatusCallback _arg0; +_arg0 = de.blinkt.openvpn.api.IOpenVPNStatusCallback.Stub.asInterface(data.readStrongBinder()); +this.unregisterStatusCallback(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_removeProfile: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +this.removeProfile(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_protectSocket: +{ +data.enforceInterface(DESCRIPTOR); +android.os.ParcelFileDescriptor _arg0; +if ((0!=data.readInt())) { +_arg0 = android.os.ParcelFileDescriptor.CREATOR.createFromParcel(data); +} +else { +_arg0 = null; +} +boolean _result = this.protectSocket(_arg0); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_addNewVPNProfile: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +boolean _arg1; +_arg1 = (0!=data.readInt()); +java.lang.String _arg2; +_arg2 = data.readString(); +de.blinkt.openvpn.api.APIVpnProfile _result = this.addNewVPNProfile(_arg0, _arg1, _arg2); +reply.writeNoException(); +if ((_result!=null)) { +reply.writeInt(1); +_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +} +else { +reply.writeInt(0); +} +return true; +} +} +return super.onTransact(code, data, reply, flags); +} +private static class Proxy implements de.blinkt.openvpn.api.IOpenVPNAPIService +{ +private android.os.IBinder mRemote; +Proxy(android.os.IBinder remote) +{ +mRemote = remote; +} +@Override public android.os.IBinder asBinder() +{ +return mRemote; +} +public java.lang.String getInterfaceDescriptor() +{ +return DESCRIPTOR; +} +@Override public java.util.List<de.blinkt.openvpn.api.APIVpnProfile> getProfiles() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +java.util.List<de.blinkt.openvpn.api.APIVpnProfile> _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getProfiles, _data, _reply, 0); +_reply.readException(); +_result = _reply.createTypedArrayList(de.blinkt.openvpn.api.APIVpnProfile.CREATOR); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public void startProfile(java.lang.String profileUUID) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(profileUUID); +mRemote.transact(Stub.TRANSACTION_startProfile, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/** Use a profile with all certificates etc. embedded,
+ * old version which does not return the UUID of the addded profile, see
+ * below for a version that return the UUID on add */ +@Override public boolean addVPNProfile(java.lang.String name, java.lang.String config) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(name); +_data.writeString(config); +mRemote.transact(Stub.TRANSACTION_addVPNProfile, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +/** start a profile using a config as inline string. Make sure that all needed data is inlined,
+ * e.g., using <ca>...</ca> or <auth-user-data>...</auth-user-data>
+ * See the OpenVPN manual page for more on inlining files */ +@Override public void startVPN(java.lang.String inlineconfig) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(inlineconfig); +mRemote.transact(Stub.TRANSACTION_startVPN, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/** This permission framework is used to avoid confused deputy style attack to the VPN
+ * calling this will give null if the app is allowed to use the external API and an Intent
+ * that can be launched to request permissions otherwise */ +@Override public android.content.Intent prepare(java.lang.String packagename) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +android.content.Intent _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(packagename); +mRemote.transact(Stub.TRANSACTION_prepare, _data, _reply, 0); +_reply.readException(); +if ((0!=_reply.readInt())) { +_result = android.content.Intent.CREATOR.createFromParcel(_reply); +} +else { +_result = null; +} +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +/** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
+ * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
+ * to let OpenVPN for Android request the permission */ +@Override public android.content.Intent prepareVPNService() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +android.content.Intent _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_prepareVPNService, _data, _reply, 0); +_reply.readException(); +if ((0!=_reply.readInt())) { +_result = android.content.Intent.CREATOR.createFromParcel(_reply); +} +else { +_result = null; +} +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +/* Disconnect the VPN */ +@Override public void disconnect() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_disconnect, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/* Pause the VPN (same as using the pause feature in the notifcation bar) */ +@Override public void pause() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/* Resume the VPN (same as using the pause feature in the notifcation bar) */ +@Override public void resume() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_resume, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/**
+ * Registers to receive OpenVPN Status Updates
+ */ +@Override public void registerStatusCallback(de.blinkt.openvpn.api.IOpenVPNStatusCallback cb) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null))); +mRemote.transact(Stub.TRANSACTION_registerStatusCallback, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/**
+ * Remove a previously registered callback interface.
+ */ +@Override public void unregisterStatusCallback(de.blinkt.openvpn.api.IOpenVPNStatusCallback cb) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null))); +mRemote.transact(Stub.TRANSACTION_unregisterStatusCallback, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/** Remove a profile by UUID */ +@Override public void removeProfile(java.lang.String profileUUID) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(profileUUID); +mRemote.transact(Stub.TRANSACTION_removeProfile, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +/** Request a socket to be protected as a VPN socket would be. Useful for creating
+ * a helper socket for an app controlling OpenVPN
+ * Before calling this function you should make sure OpenVPN for Android may actually
+ * this function by checking if prepareVPNService returns null; */ +@Override public boolean protectSocket(android.os.ParcelFileDescriptor fd) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +if ((fd!=null)) { +_data.writeInt(1); +fd.writeToParcel(_data, 0); +} +else { +_data.writeInt(0); +} +mRemote.transact(Stub.TRANSACTION_protectSocket, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +/** Use a profile with all certificates etc. embedded */ +@Override public de.blinkt.openvpn.api.APIVpnProfile addNewVPNProfile(java.lang.String name, boolean userEditable, java.lang.String config) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +de.blinkt.openvpn.api.APIVpnProfile _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(name); +_data.writeInt(((userEditable)?(1):(0))); +_data.writeString(config); +mRemote.transact(Stub.TRANSACTION_addNewVPNProfile, _data, _reply, 0); +_reply.readException(); +if ((0!=_reply.readInt())) { +_result = de.blinkt.openvpn.api.APIVpnProfile.CREATOR.createFromParcel(_reply); +} +else { +_result = null; +} +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +} +static final int TRANSACTION_getProfiles = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); +static final int TRANSACTION_startProfile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); +static final int TRANSACTION_addVPNProfile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); +static final int TRANSACTION_startVPN = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); +static final int TRANSACTION_prepare = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); +static final int TRANSACTION_prepareVPNService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); +static final int TRANSACTION_disconnect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); +static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); +static final int TRANSACTION_resume = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); +static final int TRANSACTION_registerStatusCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9); +static final int TRANSACTION_unregisterStatusCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 10); +static final int TRANSACTION_removeProfile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 11); +static final int TRANSACTION_protectSocket = (android.os.IBinder.FIRST_CALL_TRANSACTION + 12); +static final int TRANSACTION_addNewVPNProfile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 13); +} +public java.util.List<de.blinkt.openvpn.api.APIVpnProfile> getProfiles() throws android.os.RemoteException; +public void startProfile(java.lang.String profileUUID) throws android.os.RemoteException; +/** Use a profile with all certificates etc. embedded,
+ * old version which does not return the UUID of the addded profile, see
+ * below for a version that return the UUID on add */ +public boolean addVPNProfile(java.lang.String name, java.lang.String config) throws android.os.RemoteException; +/** start a profile using a config as inline string. Make sure that all needed data is inlined,
+ * e.g., using <ca>...</ca> or <auth-user-data>...</auth-user-data>
+ * See the OpenVPN manual page for more on inlining files */ +public void startVPN(java.lang.String inlineconfig) throws android.os.RemoteException; +/** This permission framework is used to avoid confused deputy style attack to the VPN
+ * calling this will give null if the app is allowed to use the external API and an Intent
+ * that can be launched to request permissions otherwise */ +public android.content.Intent prepare(java.lang.String packagename) throws android.os.RemoteException; +/** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
+ * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
+ * to let OpenVPN for Android request the permission */ +public android.content.Intent prepareVPNService() throws android.os.RemoteException; +/* Disconnect the VPN */ +public void disconnect() throws android.os.RemoteException; +/* Pause the VPN (same as using the pause feature in the notifcation bar) */ +public void pause() throws android.os.RemoteException; +/* Resume the VPN (same as using the pause feature in the notifcation bar) */ +public void resume() throws android.os.RemoteException; +/**
+ * Registers to receive OpenVPN Status Updates
+ */ +public void registerStatusCallback(de.blinkt.openvpn.api.IOpenVPNStatusCallback cb) throws android.os.RemoteException; +/**
+ * Remove a previously registered callback interface.
+ */ +public void unregisterStatusCallback(de.blinkt.openvpn.api.IOpenVPNStatusCallback cb) throws android.os.RemoteException; +/** Remove a profile by UUID */ +public void removeProfile(java.lang.String profileUUID) throws android.os.RemoteException; +/** Request a socket to be protected as a VPN socket would be. Useful for creating
+ * a helper socket for an app controlling OpenVPN
+ * Before calling this function you should make sure OpenVPN for Android may actually
+ * this function by checking if prepareVPNService returns null; */ +public boolean protectSocket(android.os.ParcelFileDescriptor fd) throws android.os.RemoteException; +/** Use a profile with all certificates etc. embedded */ +public de.blinkt.openvpn.api.APIVpnProfile addNewVPNProfile(java.lang.String name, boolean userEditable, java.lang.String config) throws android.os.RemoteException; +} diff --git a/app/gen/de/blinkt/openvpn/api/IOpenVPNStatusCallback.java b/app/gen/de/blinkt/openvpn/api/IOpenVPNStatusCallback.java new file mode 100644 index 0000000..fde3f75 --- /dev/null +++ b/app/gen/de/blinkt/openvpn/api/IOpenVPNStatusCallback.java @@ -0,0 +1,107 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + * Original file: /home/fil/workspace/RepWifiApp/src/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl + */ +package de.blinkt.openvpn.api; +/**
+ * Example of a callback interface used by IRemoteService to send
+ * synchronous notifications back to its clients. Note that this is a
+ * one-way interface so the server does not block waiting for the client.
+ */ +public interface IOpenVPNStatusCallback extends android.os.IInterface +{ +/** Local-side IPC implementation stub class. */ +public static abstract class Stub extends android.os.Binder implements de.blinkt.openvpn.api.IOpenVPNStatusCallback +{ +private static final java.lang.String DESCRIPTOR = "de.blinkt.openvpn.api.IOpenVPNStatusCallback"; +/** Construct the stub at attach it to the interface. */ +public Stub() +{ +this.attachInterface(this, DESCRIPTOR); +} +/** + * Cast an IBinder object into an de.blinkt.openvpn.api.IOpenVPNStatusCallback interface, + * generating a proxy if needed. + */ +public static de.blinkt.openvpn.api.IOpenVPNStatusCallback asInterface(android.os.IBinder obj) +{ +if ((obj==null)) { +return null; +} +android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); +if (((iin!=null)&&(iin instanceof de.blinkt.openvpn.api.IOpenVPNStatusCallback))) { +return ((de.blinkt.openvpn.api.IOpenVPNStatusCallback)iin); +} +return new de.blinkt.openvpn.api.IOpenVPNStatusCallback.Stub.Proxy(obj); +} +@Override public android.os.IBinder asBinder() +{ +return this; +} +@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException +{ +switch (code) +{ +case INTERFACE_TRANSACTION: +{ +reply.writeString(DESCRIPTOR); +return true; +} +case TRANSACTION_newStatus: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +java.lang.String _arg1; +_arg1 = data.readString(); +java.lang.String _arg2; +_arg2 = data.readString(); +java.lang.String _arg3; +_arg3 = data.readString(); +this.newStatus(_arg0, _arg1, _arg2, _arg3); +return true; +} +} +return super.onTransact(code, data, reply, flags); +} +private static class Proxy implements de.blinkt.openvpn.api.IOpenVPNStatusCallback +{ +private android.os.IBinder mRemote; +Proxy(android.os.IBinder remote) +{ +mRemote = remote; +} +@Override public android.os.IBinder asBinder() +{ +return mRemote; +} +public java.lang.String getInterfaceDescriptor() +{ +return DESCRIPTOR; +} +/**
+ * Called when the service has a new status for you.
+ */ +@Override public void newStatus(java.lang.String uuid, java.lang.String state, java.lang.String message, java.lang.String level) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(uuid); +_data.writeString(state); +_data.writeString(message); +_data.writeString(level); +mRemote.transact(Stub.TRANSACTION_newStatus, _data, null, android.os.IBinder.FLAG_ONEWAY); +} +finally { +_data.recycle(); +} +} +} +static final int TRANSACTION_newStatus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); +} +/**
+ * Called when the service has a new status for you.
+ */ +public void newStatus(java.lang.String uuid, java.lang.String state, java.lang.String message, java.lang.String level) throws android.os.RemoteException; +} diff --git a/app/gen/fil/libre/repwifiapp/R.java b/app/gen/fil/libre/repwifiapp/R.java index 581ff29..4874e0a 100644 --- a/app/gen/fil/libre/repwifiapp/R.java +++ b/app/gen/fil/libre/repwifiapp/R.java @@ -11,10 +11,6 @@ public final class R { public static final class array { public static final int debug_priority=0x7f050001; public static final int debug_priority_names=0x7f050000; - public static final int pref_example_list_titles=0x7f050002; - public static final int pref_example_list_values=0x7f050003; - public static final int pref_sync_frequency_titles=0x7f050004; - public static final int pref_sync_frequency_values=0x7f050005; } public static final class attr { } @@ -33,83 +29,123 @@ public final class R { public static final int checkmark=0x7f020002; public static final int checkmark_frame=0x7f020003; public static final int divider_shape=0x7f020004; - public static final int ic_launcher_bis=0x7f020005; - public static final int ic_stat_discon=0x7f020006; - public static final int ic_stat_repwifi=0x7f020007; - public static final int radio_button=0x7f020008; - public static final int radio_frame=0x7f020009; - public static final int repwifi_button=0x7f02000a; - public static final int repwifi_checkbox=0x7f02000b; - public static final int repwifi_progbar=0x7f02000c; - public static final int repwifi_radiobutton=0x7f02000d; - public static final int rw_prog_0=0x7f02000e; - public static final int rw_prog_1=0x7f02000f; - public static final int rw_prog_2=0x7f020010; - public static final int rw_prog_3=0x7f020011; + public static final int fil_logo=0x7f020005; + public static final int ic_launcher_bis=0x7f020006; + public static final int ic_stat_discon=0x7f020007; + public static final int ic_stat_repwifi=0x7f020008; + public static final int radio_button=0x7f020009; + public static final int radio_frame=0x7f02000a; + public static final int repwifi_button=0x7f02000b; + public static final int repwifi_checkbox=0x7f02000c; + public static final int repwifi_progbar=0x7f02000d; + public static final int repwifi_radiobutton=0x7f02000e; + public static final int rw_prog_0=0x7f02000f; + public static final int rw_prog_1=0x7f020010; + public static final int rw_prog_2=0x7f020011; + public static final int rw_prog_3=0x7f020012; } public static final class id { - public static final int btn_back=0x7f0a001d; - public static final int btn_delete=0x7f0a0015; - public static final int btn_disconnect=0x7f0a001c; - public static final int btn_hidden_ssid=0x7f0a0010; - public static final int btn_manage_nets=0x7f0a0011; - public static final int btn_next_hidden_ssid=0x7f0a000a; - public static final int btn_rescan=0x7f0a0018; - public static final int btn_scan=0x7f0a000f; - public static final int btn_select_hidden_ssid=0x7f0a0006; - public static final int chk_show_pass=0x7f0a0004; - public static final int chk_show_pass_details=0x7f0a0014; - public static final int img_logo=0x7f0a0012; - public static final int layout=0x7f0a000b; - public static final int layout_selnets=0x7f0a0016; - public static final int line=0x7f0a0007; - public static final int login_form=0x7f0a0001; - public static final int menu_config=0x7f0a0025; - public static final int menu_credits=0x7f0a0026; - public static final int menu_settings=0x7f0a0024; - public static final int pref_autoconnect=0x7f0a0021; - public static final int pref_autostart=0x7f0a0023; - public static final int pref_debug_prio=0x7f0a001e; - public static final int pref_dns1=0x7f0a001f; - public static final int pref_dns2=0x7f0a0020; - public static final int pref_progbar=0x7f0a0022; - public static final int progbar=0x7f0a000c; - public static final int scrollview=0x7f0a0019; - public static final int sign_in_button=0x7f0a0005; - public static final int table_networks=0x7f0a001a; - public static final int txt_credits=0x7f0a0000; - public static final int txt_insert_pass=0x7f0a0002; - public static final int txt_insert_ssid=0x7f0a0008; - public static final int txt_main=0x7f0a000e; - public static final int txt_msg=0x7f0a000d; - public static final int txt_net_details=0x7f0a0013; - public static final int txt_password=0x7f0a0003; - public static final int txt_selnets=0x7f0a0017; - public static final int txt_ssid=0x7f0a0009; - public static final int txt_status=0x7f0a001b; + public static final int btn_back=0x7f0a0016; + public static final int btn_delete=0x7f0a0023; + public static final int btn_disconnect=0x7f0a002a; + public static final int btn_hidden_ssid=0x7f0a001c; + public static final int btn_ip_settings=0x7f0a0021; + public static final int btn_manage_nets=0x7f0a001d; + public static final int btn_next_hidden_ssid=0x7f0a000c; + public static final int btn_rescan=0x7f0a0026; + public static final int btn_save_ip_settings=0x7f0a0015; + public static final int btn_save_vpn_settings=0x7f0a002d; + public static final int btn_scan=0x7f0a001b; + public static final int btn_select_hidden_ssid=0x7f0a0008; + public static final int btn_vpn_settings=0x7f0a0022; + public static final int chk_show_pass=0x7f0a0006; + public static final int chk_show_pass_details=0x7f0a0020; + public static final int chk_use_dhcp=0x7f0a000e; + public static final int img_logo=0x7f0a001e; + public static final int img_logo_fil=0x7f0a0001; + public static final int layout=0x7f0a0017; + public static final int layout_selnets=0x7f0a0024; + public static final int lbl_gateway=0x7f0a0013; + public static final int lbl_ip_settings=0x7f0a000d; + public static final int lbl_netmask=0x7f0a0011; + public static final int lbl_static_ip=0x7f0a000f; + public static final int lbl_vpn_settings=0x7f0a002b; + public static final int line=0x7f0a0009; + public static final int login_form=0x7f0a0003; + public static final int menu_btn_closeapp=0x7f0a0035; + public static final int menu_config=0x7f0a0036; + public static final int menu_credits=0x7f0a0037; + public static final int menu_settings=0x7f0a0034; + public static final int pref_autoconnect=0x7f0a0031; + public static final int pref_autostart=0x7f0a0033; + public static final int pref_debug_prio=0x7f0a002e; + public static final int pref_dns1=0x7f0a002f; + public static final int pref_dns2=0x7f0a0030; + public static final int pref_progbar=0x7f0a0032; + public static final int progbar=0x7f0a0018; + public static final int scrollview=0x7f0a0027; + public static final int sign_in_button=0x7f0a0007; + public static final int spin_vpn_profile=0x7f0a002c; + public static final int table_networks=0x7f0a0028; + public static final int txt_credits=0x7f0a0002; + public static final int txt_credits_title=0x7f0a0000; + public static final int txt_gateway=0x7f0a0014; + public static final int txt_insert_pass=0x7f0a0004; + public static final int txt_insert_ssid=0x7f0a000a; + public static final int txt_main=0x7f0a001a; + public static final int txt_msg=0x7f0a0019; + public static final int txt_net_details=0x7f0a001f; + public static final int txt_netmask=0x7f0a0012; + public static final int txt_password=0x7f0a0005; + public static final int txt_selnets=0x7f0a0025; + public static final int txt_ssid=0x7f0a000b; + public static final int txt_static_ip=0x7f0a0010; + public static final int txt_status=0x7f0a0029; } public static final class layout { public static final int activity_credits=0x7f030000; public static final int activity_input_password=0x7f030001; public static final int activity_input_ssid=0x7f030002; - public static final int activity_long_task=0x7f030003; - public static final int activity_main=0x7f030004; - public static final int activity_network_details=0x7f030005; - public static final int activity_select_network=0x7f030006; - public static final int activity_settings=0x7f030007; - public static final int activity_show_status=0x7f030008; + public static final int activity_ipv4_settings=0x7f030003; + public static final int activity_long_task=0x7f030004; + public static final int activity_main=0x7f030005; + public static final int activity_network_details=0x7f030006; + public static final int activity_select_network=0x7f030007; + public static final int activity_settings=0x7f030008; + public static final int activity_show_status=0x7f030009; + public static final int activity_vpn_settings=0x7f03000a; } public static final class menu { public static final int activity_input_ssid=0x7f090000; - public static final int activity_main=0x7f090001; + public static final int activity_ipv4_settings=0x7f090001; + public static final int activity_main=0x7f090002; + public static final int activity_vpn_settings=0x7f090003; } public static final class string { - public static final int action_sign_in_register=0x7f07002a; - public static final int action_sign_in_short=0x7f07002b; + /** + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + + */ public static final int app_name=0x7f070000; public static final int back_main=0x7f07000b; - public static final int button_text_next=0x7f070005; - public static final int confirm_kill_backend=0x7f070025; + public static final int button_text_next=0x7f070006; + public static final int confirm_exit_app=0x7f070025; + public static final int confirm_kill_backend=0x7f070026; public static final int confirm_reset_settings=0x7f070024; public static final int connect_hidden=0x7f07001c; public static final int credit_text=0x7f070013; @@ -117,66 +153,149 @@ public final class R { public static final int disconnect=0x7f07000c; public static final int dns1_default=0x7f070021; public static final int dns2_default=0x7f070022; - public static final int error_field_required=0x7f070031; - public static final int error_incorrect_password=0x7f070030; - public static final int error_invalid_email=0x7f07002e; - public static final int error_invalid_password=0x7f07002f; public static final int force_disconnect=0x7f07000d; - public static final int hello_world=0x7f070009; + public static final int hello_world=0x7f070070; public static final int input_ssid=0x7f07001d; - public static final int insert_nets_password=0x7f070006; - public static final int login_progress_signing_in=0x7f07002d; + public static final int insert_nets_password=0x7f070007; public static final int manage_networks=0x7f070011; + public static final int menu_closeapp=0x7f070002; public static final int menu_config=0x7f070014; public static final int menu_credits=0x7f070001; - public static final int menu_forgot_password=0x7f07002c; public static final int menu_settings=0x7f07001f; + public static final int msg_autoconnect_error=0x7f070037; + public static final int msg_checking_status=0x7f070030; public static final int msg_confirm_delete_network=0x7f070016; + public static final int msg_connect_fail=0x7f070034; + public static final int msg_connected_to=0x7f070041; + public static final int msg_connecting_to=0x7f07002d; + public static final int msg_disconnect_fail=0x7f070044; + public static final int msg_disconnected=0x7f070043; + public static final int msg_error_ip_format=0x7f070040; public static final int msg_interface_not_found=0x7f070015; + public static final int msg_invalid_gateway=0x7f070066; + public static final int msg_invalid_ip=0x7f070064; + public static final int msg_invalid_netmask=0x7f070065; + public static final int msg_log_save_fail=0x7f07003f; + public static final int msg_log_saved=0x7f07003e; + public static final int msg_netinfo_delete_fail=0x7f070036; + public static final int msg_netinfo_deleted=0x7f070035; + public static final int msg_network_list_fail=0x7f07003a; + public static final int msg_network_name_empty=0x7f07002c; + public static final int msg_network_save_fail=0x7f070033; + public static final int msg_network_saved=0x7f070032; + public static final int msg_no_network=0x7f07003b; + public static final int msg_no_saved_network=0x7f070046; + public static final int msg_os_unsupported=0x7f070048; + public static final int msg_password_empty=0x7f07002a; + public static final int msg_please_wait=0x7f070031; public static final int msg_root_denied=0x7f07001b; public static final int msg_root_disabled=0x7f07001a; + public static final int msg_scanning_for_nets=0x7f07002f; + public static final int msg_select_network_connect=0x7f07003c; + public static final int msg_select_network_manage=0x7f07003d; + public static final int msg_touch_open=0x7f070047; + public static final int msg_vpn_connect_error=0x7f07006e; + public static final int msg_vpn_disconnect=0x7f070068; + public static final int msg_vpn_disconnect_error=0x7f070067; + public static final int msg_vpn_launched=0x7f070069; + public static final int msg_vpn_no_permission=0x7f07006d; + public static final int msg_vpn_no_profile=0x7f070073; + public static final int msg_vpn_wrong_profile=0x7f07006a; public static final int no=0x7f070018; - public static final int pref_default_display_name=0x7f070037; - public static final int pref_description_social_recommendations=0x7f070035; - /** Example settings for Data & Sync - */ - public static final int pref_header_data_sync=0x7f070039; - /** Strings related to Settings - Example General settings - */ - public static final int pref_header_general=0x7f070033; - /** Example settings for Notifications - */ - public static final int pref_header_notifications=0x7f07003c; - public static final int pref_ringtone_silent=0x7f07003f; - public static final int pref_title_add_friends_to_messages=0x7f070038; - public static final int pref_title_display_name=0x7f070036; - public static final int pref_title_new_message_notifications=0x7f07003d; - public static final int pref_title_ringtone=0x7f07003e; - public static final int pref_title_social_recommendations=0x7f070034; - public static final int pref_title_sync_frequency=0x7f07003a; - public static final int pref_title_system_sync_settings=0x7f07003b; - public static final int pref_title_vibrate=0x7f070040; - /** Strings related to login - */ - public static final int prompt_email=0x7f070028; - public static final int prompt_password=0x7f070029; public static final int receiver_description=0x7f070023; - public static final int rescan=0x7f070004; + public static final int rescan=0x7f070005; public static final int retry=0x7f070019; - public static final int scan_networks=0x7f070002; + public static final int scan_networks=0x7f070003; public static final int select_saved_net=0x7f070020; - public static final int show_password=0x7f070007; - public static final int summary_kill_backend=0x7f070026; - public static final int title_activity_connect=0x7f070008; + public static final int show_password=0x7f070008; + public static final int summary_advanced_settings=0x7f07005a; + public static final int summary_autoconnect=0x7f070051; + public static final int summary_dns1=0x7f07004e; + public static final int summary_dns2=0x7f07004f; + public static final int summary_general_settings=0x7f07005b; + public static final int summary_kill_backend=0x7f070027; + public static final int summary_progbar=0x7f070053; + public static final int summary_restore_default=0x7f070057; + public static final int summary_start_at_boot=0x7f070055; + public static final int summary_vpn_settings=0x7f070072; + public static final int text_gateway=0x7f070060; + public static final int text_ip_address=0x7f070042; + public static final int text_ipv4_settings=0x7f07005d; + public static final int text_netinfo_last_used=0x7f070038; + public static final int text_password=0x7f070039; + public static final int text_presented_by=0x7f070028; + public static final int text_static_ip=0x7f07005e; + public static final int text_status=0x7f070045; + public static final int text_subnet_mask=0x7f07005f; + public static final int text_use_dhcp=0x7f07005c; + public static final int text_vpn_package_missing=0x7f07006c; + public static final int title_activity_connect=0x7f070009; public static final int title_activity_credits=0x7f070012; - public static final int title_activity_input_password=0x7f070027; + /** + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + + */ + public static final int title_activity_input_password=0x7f070074; public static final int title_activity_input_ssid=0x7f07001e; + public static final int title_activity_ipv4_settings=0x7f070061; public static final int title_activity_long_task=0x7f07000e; public static final int title_activity_manage_networks=0x7f07000f; - public static final int title_activity_select_network=0x7f070003; - public static final int title_activity_settings=0x7f070032; + public static final int title_activity_select_network=0x7f070004; + /** + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + + */ + public static final int title_activity_settings=0x7f070075; public static final int title_activity_show_status=0x7f07000a; + public static final int title_activity_vpn_settings=0x7f07006f; + public static final int title_advanced_settings=0x7f070058; + public static final int title_autoconnect=0x7f070050; + public static final int title_dns_1=0x7f07004c; + public static final int title_dns_2=0x7f07004d; + public static final int title_dump_logs=0x7f07004a; + public static final int title_general_settings=0x7f070059; + public static final int title_input_password=0x7f070029; + public static final int title_input_ssid=0x7f07002b; + public static final int title_log_prio=0x7f070049; + public static final int title_progbar=0x7f070052; + public static final int title_reset_backend=0x7f07004b; + public static final int title_restore_default=0x7f070056; + public static final int title_scanning=0x7f07002e; + public static final int title_start_at_boot=0x7f070054; + public static final int title_vpn_settings=0x7f07006b; + public static final int txt_back=0x7f070063; + public static final int txt_save=0x7f070071; + public static final int txt_save_ip_settings=0x7f070062; public static final int yes=0x7f070017; } public static final class style { diff --git a/app/res/drawable/fil_logo.png b/app/res/drawable/fil_logo.png Binary files differnew file mode 100644 index 0000000..d862888 --- /dev/null +++ b/app/res/drawable/fil_logo.png diff --git a/app/res/layout/activity_credits.xml b/app/res/layout/activity_credits.xml index 04280d4..d114ce1 100644 --- a/app/res/layout/activity_credits.xml +++ b/app/res/layout/activity_credits.xml @@ -1,16 +1,44 @@ -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@color/ThemeDark" - android:orientation="vertical" > + android:background="@color/black" + android:padding="15dp" > + + <TextView + android:id="@+id/txt_credits_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:padding="2dp" + android:text="@string/text_presented_by" + android:textColor="@color/ThemeLight" + android:textColorLink="@color/ThemeLight" + android:textIsSelectable="true" + android:textSize="9pt" /> + + <ImageView + android:id="@+id/img_logo_fil" + android:layout_width="100dp" + android:layout_height="110dp" + android:layout_below="@id/txt_credits_title" + android:layout_centerHorizontal="true" + android:layout_margin="1dp" + android:contentDescription="fil\'s logo" + android:src="@drawable/fil_logo" > + </ImageView> <TextView android:id="@+id/txt_credits" android:layout_width="fill_parent" android:layout_height="fill_parent" + android:layout_below="@id/img_logo_fil" + android:layout_centerHorizontal="true" + android:padding="15dp" android:scrollbars="vertical" + android:fadeScrollbars="false" android:textColor="@color/ThemeLight" android:textColorLink="@color/ThemeLight" + android:textIsSelectable="true" android:textSize="7pt" /> -</LinearLayout>
\ No newline at end of file +</RelativeLayout>
\ No newline at end of file diff --git a/app/res/layout/activity_ipv4_settings.xml b/app/res/layout/activity_ipv4_settings.xml new file mode 100644 index 0000000..5c0887c --- /dev/null +++ b/app/res/layout/activity_ipv4_settings.xml @@ -0,0 +1,126 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/black" + android:padding="15dp" + tools:context=".Ipv4SettingsActivity" > + + <TextView + android:id="@+id/lbl_ip_settings" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:background="@color/black" + android:text="@string/text_ipv4_settings" + android:textColor="@color/ThemeLight" + android:textSize="12pt" /> + + <CheckBox + android:id="@+id/chk_use_dhcp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/lbl_ip_settings" + android:layout_margin="10dp" + android:text="@string/text_use_dhcp" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <TextView + android:id="@+id/lbl_static_ip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/chk_use_dhcp" + android:layout_margin="10dp" + android:background="@color/black" + android:text="@string/text_ip_address" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <EditText + android:id="@+id/txt_static_ip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/chk_use_dhcp" + android:layout_margin="10dp" + android:layout_toRightOf="@id/lbl_static_ip" + android:background="@drawable/button_bg" + android:inputType="text" + android:padding="5pt" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <TextView + android:id="@+id/lbl_netmask" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/txt_static_ip" + android:layout_margin="10dp" + android:background="@color/black" + android:text="@string/text_subnet_mask" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <EditText + android:id="@+id/txt_netmask" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/txt_static_ip" + android:layout_margin="10dp" + android:layout_toRightOf="@id/lbl_netmask" + android:background="@drawable/button_bg" + android:inputType="text" + android:padding="5pt" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <TextView + android:id="@+id/lbl_gateway" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/txt_netmask" + android:layout_margin="10dp" + android:background="@color/black" + android:text="@string/text_gateway" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <EditText + android:id="@+id/txt_gateway" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/txt_netmask" + android:layout_margin="10dp" + android:layout_toRightOf="@id/lbl_gateway" + android:background="@drawable/button_bg" + android:inputType="text" + android:padding="5pt" + android:textColor="@color/ThemeLight" + android:textSize="9pt" /> + + <Button + android:id="@+id/btn_save_ip_settings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/txt_gateway" + android:layout_centerHorizontal="true" + android:layout_marginTop="25dp" + android:background="@drawable/repwifi_button" + android:onClick="btnSaveClick" + android:text="@string/txt_save_ip_settings" + android:textColor="@color/ThemeLight" /> + + <Button + android:id="@+id/btn_back" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/btn_save_ip_settings" + android:layout_centerHorizontal="true" + android:layout_marginTop="15dp" + android:background="@drawable/repwifi_button" + android:onClick="btnBackClick" + android:text="@string/txt_back" + android:textColor="@color/ThemeLight" /> + + +</RelativeLayout>
\ No newline at end of file diff --git a/app/res/layout/activity_long_task.xml b/app/res/layout/activity_long_task.xml index a17ba32..46d0a12 100644 --- a/app/res/layout/activity_long_task.xml +++ b/app/res/layout/activity_long_task.xml @@ -22,6 +22,7 @@ android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:padding="10dp" + android:textIsSelectable="false" android:textColor="@color/ThemeLight" /> </RelativeLayout>
\ No newline at end of file diff --git a/app/res/layout/activity_network_details.xml b/app/res/layout/activity_network_details.xml index 6442585..225e59d 100644 --- a/app/res/layout/activity_network_details.xml +++ b/app/res/layout/activity_network_details.xml @@ -13,6 +13,7 @@ android:layout_margin="10dp" android:background="@color/black" android:textColor="@color/ThemeLight" + android:textIsSelectable="true" android:textSize="7pt" /> <CheckBox @@ -25,13 +26,37 @@ android:textSize="10pt" /> <Button - android:id="@+id/btn_delete" + android:id="@+id/btn_ip_settings" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/chk_show_pass_details" android:layout_centerHorizontal="true" android:layout_marginTop="15dp" android:background="@drawable/repwifi_button" + android:onClick="btnIpSettingsClick" + android:text="@string/text_ipv4_settings" + android:textColor="@color/ThemeLight" /> + + <Button + android:id="@+id/btn_vpn_settings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/btn_ip_settings" + android:layout_centerHorizontal="true" + android:layout_marginTop="15dp" + android:background="@drawable/repwifi_button" + android:onClick="btnVpnSettingsClick" + android:text="@string/title_activity_vpn_settings" + android:textColor="@color/ThemeLight" /> + + <Button + android:id="@+id/btn_delete" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/btn_vpn_settings" + android:layout_centerHorizontal="true" + android:layout_marginTop="15dp" + android:background="@drawable/repwifi_button" android:onClick="btnDeleteClick" android:text="@string/delete" android:textColor="@color/ThemeLight" /> diff --git a/app/res/layout/activity_vpn_settings.xml b/app/res/layout/activity_vpn_settings.xml new file mode 100644 index 0000000..4378baa --- /dev/null +++ b/app/res/layout/activity_vpn_settings.xml @@ -0,0 +1,55 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/black" + android:padding="15dp" + tools:context=".Ipv4SettingsActivity" > + + <TextView + android:id="@+id/lbl_vpn_settings" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:background="@color/black" + android:textColor="@color/ThemeLight" + android:textIsSelectable="false" + android:textSize="9pt" /> + + <Spinner + android:id="@+id/spin_vpn_profile" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/lbl_vpn_settings" + android:layout_margin="10dp" + android:background="@drawable/button_bg" + android:inputType="text" + android:padding="1pt" + android:textColor="@color/ThemeLight" + android:textSize="10pt" /> + + <Button + android:id="@+id/btn_save_vpn_settings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/spin_vpn_profile" + android:layout_centerHorizontal="true" + android:layout_marginTop="25dp" + android:background="@drawable/repwifi_button" + android:onClick="btnSaveClick" + android:text="@string/txt_save" + android:textColor="@color/ThemeLight" /> + + <Button + android:id="@+id/btn_back" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/btn_save_vpn_settings" + android:layout_centerHorizontal="true" + android:layout_marginTop="15dp" + android:background="@drawable/repwifi_button" + android:onClick="btnBackClick" + android:text="@string/txt_back" + android:textColor="@color/ThemeLight" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/app/res/menu/activity_ipv4_settings.xml b/app/res/menu/activity_ipv4_settings.xml new file mode 100644 index 0000000..77f358b --- /dev/null +++ b/app/res/menu/activity_ipv4_settings.xml @@ -0,0 +1,9 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/menu_settings" + android:orderInCategory="100" + android:showAsAction="never" + android:title="@string/menu_settings"/> + +</menu>
\ No newline at end of file diff --git a/app/res/menu/activity_main.xml b/app/res/menu/activity_main.xml index e9a1624..430a0b0 100644 --- a/app/res/menu/activity_main.xml +++ b/app/res/menu/activity_main.xml @@ -4,14 +4,20 @@ android:textColor="@color/ThemeLight" > <item - android:id="@+id/menu_config" + android:id="@+id/menu_btn_closeapp" android:orderInCategory="1" android:showAsAction="never" android:textColor="@color/ThemeLight" + android:title="@string/menu_closeapp"/> + <item + android:id="@+id/menu_config" + android:orderInCategory="2" + android:showAsAction="never" + android:textColor="@color/ThemeLight" android:title="@string/menu_config"/> <item android:id="@+id/menu_credits" - android:orderInCategory="2" + android:orderInCategory="3" android:showAsAction="never" android:textColor="@color/ThemeLight" android:title="@string/menu_credits"/> diff --git a/app/res/menu/activity_vpn_settings.xml b/app/res/menu/activity_vpn_settings.xml new file mode 100644 index 0000000..77f358b --- /dev/null +++ b/app/res/menu/activity_vpn_settings.xml @@ -0,0 +1,9 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/menu_settings" + android:orderInCategory="100" + android:showAsAction="never" + android:title="@string/menu_settings"/> + +</menu>
\ No newline at end of file diff --git a/app/res/values-fr/strings.xml b/app/res/values-fr/strings.xml index 0801a44..ad561bf 100644 --- a/app/res/values-fr/strings.xml +++ b/app/res/values-fr/strings.xml @@ -2,26 +2,27 @@ <resources> <!-- - RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> - French translation is Copyright (C) 2017 Nicola Spanti + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti - This file is part of RepWifiApp. - RepWifiApp is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - RepWifiApp is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --> <string name="app_name">RepWifi</string> <string name="menu_credits">Info et crédits</string> + <string name="menu_closeapp">Tuer RepWifi</string> <string name="scan_networks">Scan des réseaux</string> <string name="title_activity_select_network">Selectionner un réseau</string> <string name="rescan">Répéter le scan</string> @@ -29,9 +30,8 @@ <string name="insert_nets_password">Fournisser un mot de passe pour se connecter à :</string> <string name="show_password">Montrer le mot de passe</string> <string name="title_activity_connect">ActivitéDeConnexion</string> - <string name="hello_world">Bonjour le monde !</string> - <string name="title_activity_show_status">Statur de connexion</string> - <!--<string name="back_main">Revenir au main</string>--> + <string name="title_activity_show_status">Statut de connexion</string> + <string name="back_main">Revenir au menu principal</string> <string name="disconnect">Déconnecter</string> <string name="force_disconnect">Forcer la déconnection</string> <string name="title_activity_long_task">ActivitéDeTâcheLongue</string> @@ -39,7 +39,7 @@ <string name="delete">Supprimer les informations sur le réseau</string> <string name="manage_networks">Gérer les réseaux</string> <string name="title_activity_credits">Crédits</string> - <string name="credit_text">Copyright 2017 Filippo \"Fil\" Bergamo<br/><br/>Cette app est du logiciel libre.<br/>Elle est sous licence <a href="https://www.gnu.org/licenses/gpl.txt">GPL v3</a><br/><br/>Cette app est développé en tant que contribution au <br/><a href="https://www.replicant.us">projet Replicant</a><br/><br/><b><u><big>Merci GNUs:</big></u></b><br/><br/><b>Tiberiu - Technoethical</b><br/>pour avoir fait le travail initial de porter le Wi-Fi sur Replicant 4.2.<br/><br/><b>Wolfgang Wiedmeyer</b><br/>pour le portage du Wi-Fi libre sur Replicant 6.0 et pour l\'aide sur les scripts.<br/><br/>Pour reporter des bogues, demander des fonctionnalités, ou n\'importe quelle demande d\'aide, veuillez vous adresser à :<br/><a href="https://redmine.replicant.us/projects/replicant/boards">Le forum de Replicant</a><br/><br/>Le code source est hébergé sur : <br/><a href="https://git.replicant.us/contrib/Fil/RepWifiApp/">https://git.replicant.us/contrib/Fil/RepWifiApp/</a><br/></string> + <string name="credit_text">Copyright 2017 Filippo \"Fil\" Bergamo<br/><br/>Cette app est du logiciel libre.<br/>Elle est sous licence <a href="https://www.gnu.org/licenses/gpl.txt">GPL v3</a><br/><br/>Cette app est développé en tant que contribution au <br/><a href="https://www.replicant.us">projet Replicant</a><br/>Pour signaler des bogues, demander des fonctionnalités, ou n\'importe quelle autre demande d\'aide, veuillez vous référer à :<br/><a href="https://redmine.replicant.us/projects/replicant/boards">Forum de Replicant</a><br/><br/>Le code source est hébergé sur : <br/><a href="https://git.replicant.us/contrib/Fil/RepWifiApp/">https://git.replicant.us/contrib/Fil/RepWifiApp/</a><br/><br/><b><u><big>Merci GNUs:</big></u></b><br/><br/><b>Tiberiu - Technoethical</b><br/>pour avoir fait le travail initial de porter le Wi-Fi sur Replicant 4.2.<br/><br/><b>Wolfgang Wiedmeyer</b><br/>pour le portage du Wi-Fi libre sur Replicant 6.0 et pour l\'aide sur les scripts.<br/><br/><b>Nicola Spanti</b><br/>pour la traduction en français.<br/><br/><b>Nichlas Severinsen</b><br/>pour la publication de cette app sur F-Droid.<br/><br/></string> <string name="menu_config">Paramètres</string> <string name="msg_interface_not_found">Pas d\'adaptateur Wi-Fi trouvé !\nVeuillez connecter un adaptateur Wi-Fi géréet réessayer.</string> <string name="msg_confirm_delete_network">Êtes vous sûr de vouloir supprimer ce réseau ?</string> @@ -52,9 +52,87 @@ <string name="input_ssid">Ou.. Fournisser le nom du réseau (SSID)</string> <string name="title_activity_input_ssid">Fournisser le nom du réseau</string> <string name="menu_settings">Paramètres</string> - <string name="select_saved_net">Utiliser le réseau sauvegardé</string> + <string name="select_saved_net">Utiliser le réseau enregistré</string> <string name="receiver_description">RepWifi est attentif à l\'événement de démarrage. Cela lui permet d\'avoir une fonctionnalité de démarrage automatique et une autre lié aux notifications.</string> <string name="confirm_reset_settings">Êtes vous sûr de vouloir de remettre tous les paramètres aux valeurs par défaut ?</string> + <string name="confirm_exit_app">Êtes vous sûr de vouloir tuer RepWifi ? Cela vous déconnectera du Wi-Fi.</string> <string name="confirm_kill_backend">Êtes vous sûr de vouloir tuer les processus d\'arrière-plan ?</string> <string name="summary_kill_backend">Des fois les programmes d\'arrière-plan restent coincés dans des états incohérents.\nCliquer sur le boutton restaure le comportement normal en tuant les instances en cours de wpa_supplicant et dhcpcd.</string> + <string name="text_presented_by">Fait par :</string> + <string name="title_input_password">Saisir le mot de passe</string> + <string name="msg_password_empty">Le mot de passe ne peut pas être nul !</string> + <string name="title_input_ssid">Saisir les paramètres du réseau</string> + <string name="msg_network_name_empty">Le nom du réseau ne peut pas être nul !</string> + <string name="msg_connecting_to">Connexion à </string> + <string name="title_scanning">Scan...</string> + <string name="msg_scanning_for_nets">Scan pour trouver des réseaux...</string> + <string name="msg_checking_status">Vérification du statut...</string> + <string name="msg_please_wait">Veuillez attendre...</string> + <string name="msg_network_saved">Réseau enregistré !</string> + <string name="msg_network_save_fail">ÉCHEC à l\'enregistrement du réseau !</string> + <string name="msg_connect_fail">ÉCHEC à la connexion !</string> + <string name="msg_netinfo_deleted">Informations sur le réseau supprimées !</string> + <string name="msg_netinfo_delete_fail">ÉCHEC à la suppresion des informations sur le réseau !</string> + <string name="msg_autoconnect_error">Il y a eu une erreur pendant la tentative d\'auto-connexion</string> + <string name="text_netinfo_last_used">Dernier utilisé</string> + <string name="text_password">Mot de passe</string> + <string name="msg_network_list_fail">Impossible d\'avoir la liste des réseaux !</string> + <string name="msg_no_network">Aucun réseau trouvé.</string> + <string name="msg_select_network_connect">Choisir le réseau auquel vous voulez vous connecter :</string> + <string name="msg_select_network_manage">Choisir les informations de réseau à gérer :</string> + <string name="msg_log_saved">Journaux enregistrés dans un ficher</string> + <string name="msg_log_save_fail">Échec à l\'enregistrement du journal dans un fichier !</string> + <string name="msg_error_ip_format">ERREUR :\nMauvais format d\'IP !</string> + <string name="msg_connected_to">Connecté à </string> + <string name="text_ip_address">Adresse IP</string> + <string name="msg_disconnected">Déconnecté.</string> + <string name="msg_disconnect_fail">Échec à la déconnexion !</string> + <string name="text_status">Statut</string> + <string name="msg_no_saved_network">Aucun réseau enregistré</string> + <string name="msg_touch_open">Cliquer pour ouvrir.</string> + <string name="msg_os_unsupported">VERSION DE SYSTÈME D\'EXPLOITATION NON SUPPORTÉ\nLa version actuelle de Replicant n\'est pas supportée par RepWifi.\nVeuillez mettre à jour à la dernière version aussitôt que possible !</string> + <string name="title_log_prio">Priorité du journal</string> + <string name="title_dump_logs">Enregistrer les journaux dans un fichier</string> + <string name="title_reset_backend">Réinitialiser le moteur en arrière-plan</string> + <string name="title_dns_1">Serveur DNS #1</string> + <string name="title_dns_2">Serveur DNS #2</string> + <string name="summary_dns1">Définir l\'adresse IPv4 du serveur DNS primaire.\nSi c\'est laissé vide, RepWifi va essayer d\'utiliser la passerelle par défaut comme résolveur DNS.</string> + <string name="summary_dns2">Définir l\'adresse IPv4 du serveur DNS secondaire.\nSi la première adresse est vide, la valeur de ce champ va être ignorée.</string> + <string name="title_autoconnect">Activer l\'auto-connexion</string> + <string name="summary_autoconnect">Quand l\'adaptateur Wi-Fi est connecté, RepWifi se connecte automatiquement aux réseaux connus atteignables.\n(Expérimental).</string> + <string name="title_progbar">Barre de progression animée</string> + <string name="summary_progbar">Affiche une barre de progression animée pendant que des tâches de fond sont réalisées.\nGarder la désactivée pour (à priori) économiser de l\'énergie pour l\'adaptateur Wi-Fi.</string> + <string name="title_start_at_boot">Activer le démarrage automatique au démarrage du système</string> + <string name="summary_start_at_boot">Si coché, RepWifi démarre automatiquement quand le système démarre.</string> + <string name="title_restore_default">Rétablir les paramètres par défaut</string> + <string name="summary_restore_default">cliquer pour rétablir les paramètres par défaut\n(ensuite revenez à l\'écran principal pour appliquer la réinitialisation)</string> + <string name="title_advanced_settings">Avancé & Débogage</string> + <string name="title_general_settings">Options</string> + <string name="summary_advanced_settings">définir les options avancées et variables de débogage</string> + <string name="summary_general_settings">définir les options générales</string> + <string name="text_use_dhcp">Utiliser DHCP</string> + <string name="text_ipv4_settings">Paramètres IPv4</string> + <string name="text_static_ip">IP statique</string> + <string name="text_subnet_mask">Masque de sous-réseau</string> + <string name="text_gateway">Passerelle</string> + <string name="title_activity_ipv4_settings">ActivitéDesParamètresIpv4</string> + <string name="txt_save_ip_settings">Enregistrer les paramètres IP</string> + <string name="txt_back">Retour</string> + <string name="msg_invalid_ip">Adresse IP invalide !</string> + <string name="msg_invalid_netmask">Sous-réseau invalide !</string> + <string name="msg_invalid_gateway">Passerelle invalide !</string> + <string name="msg_vpn_disconnect_error">ERREUR pendant la déconnexion du VPN !</string> + <string name="msg_vpn_disconnect">Déconnecté du VPN</string> + <string name="msg_vpn_launched">Démarrage de la connexion au VPN</string> + <string name="msg_vpn_wrong_profile">Nom de profil invalide !</string> + <string name="title_vpn_settings">Paramètres du VPN</string> + <string name="text_vpn_package_missing">Il semble que l\'app VPN nécessaire n\'est pas installée.\nRepWifi a besoin que l\'app "[VPN_EXT_APP]" soit installée, pour pouvoir fournir la fonctionnalité VPN.\nVeuillez installer "[VPN_EXT_APP]" et réessayer.</string> + <string name="msg_vpn_no_permission">Permission VPN refusée.\nVous devez accorder à RepWifi la permission d\'utiliser l\'app "[VPN_EXT_APP]" quand cela vous est demandé.\nRepWifi ne sera pas capable de démarrer le VPN tant que vous ne l\'aurez pas fait.</string> + <string name="msg_vpn_connect_error">** ERREUR pendant la connexion au VPN **</string> + <string name="title_activity_vpn_settings">Paramètres du VPN</string> + <string name="hello_world">Bonjour le monde !</string> + <string name="txt_save">Enregistrer</string> + <string name="summary_vpn_settings">Choisir le nom du profil VPN que vous voulez qui soit lancé automatiquement quand vous vous connecter à ce réseau.\nLaisser vide pour désactiver la connexion automatique au VPN.\nPour utiliser la fonction VPN, l\'app "[VPN_EXT_APP]" doit être installée sur le système.</string> + <string name="msg_vpn_no_profile">Aucun profil trouvé.\nVeuillez ajouter un profil VPN dans l\'app [VPN_EXT_APP] avant d\'utiliser cette fonctionnalité.</string> + </resources> diff --git a/app/res/values-fr/strings_activity_input_password.xml b/app/res/values-fr/strings_activity_input_password.xml index 17f78cd..c27ca7a 100644 --- a/app/res/values-fr/strings_activity_input_password.xml +++ b/app/res/values-fr/strings_activity_input_password.xml @@ -2,35 +2,24 @@ <resources> <!-- - RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> - French translation is Copyright (C) 2017 Nicola Spanti + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti - This file is part of RepWifiApp. - RepWifiApp is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - RepWifiApp is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --> <string name="title_activity_input_password">Entrer le mot de passe pour le réseau</string> - <!-- Strings related to login --> - <string name="prompt_email">Email</string> - <string name="prompt_password">Mot de passe</string> - <string name="action_sign_in_register"><b>S\'identifier</b> ou s\'enregistrer</string> - <string name="action_sign_in_short">S\'identifier</string> - <string name="menu_forgot_password">Récupérer un mot de passe perdu</string> - <string name="login_progress_signing_in">Identification…</string> - <string name="error_invalid_email">Cette adresse email est invalide</string> - <string name="error_invalid_password">Ce mot de passe est trop court</string> - <string name="error_incorrect_password">Ce mot de passe est incorrect</string> - <string name="error_field_required">Ce champ est obligatoire</string> </resources> diff --git a/app/res/values-fr/strings_activity_settings.xml b/app/res/values-fr/strings_activity_settings.xml index 6e8610b..260bcb0 100644 --- a/app/res/values-fr/strings_activity_settings.xml +++ b/app/res/values-fr/strings_activity_settings.xml @@ -2,62 +2,24 @@ <resources> <!-- - RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> - French translation is Copyright (C) 2017 Nicola Spanti + This file is part of RepWifiApp. + RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> + French translation is Copyright (C) 2017 Nicola Spanti - This file is part of RepWifiApp. - RepWifiApp is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - RepWifiApp is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --> <string name="title_activity_settings">Paramètres</string> - <!-- Strings related to Settings --> - - - <!-- Example General settings --> - <string name="pref_header_general">Général</string> - <string name="pref_title_social_recommendations">Activer les recommendations sociales</string> - <string name="pref_description_social_recommendations">Recommendations pour que les gens puissent vous contacter en se basant sur votre historique de messages</string> - <string name="pref_title_display_name">Afficher le nom</string> - <string name="pref_default_display_name">John Smith</string> - <string name="pref_title_add_friends_to_messages">Ajouter des ami·e·s aux messages</string> - - <string-array name="pref_example_list_titles"> - <item>Toujours</item> - <item>Quand c\'est possible</item> - <item>Jamais</item> - </string-array> - - <!-- Example settings for Data & Sync --> - <string name="pref_header_data_sync">Données & synchronisation</string> - <string name="pref_title_sync_frequency">Fréquence de la synchronisation</string> - - <string-array name="pref_sync_frequency_titles"> - <item>15 minutes</item> - <item>30 minutes</item> - <item>1 heure</item> - <item>3 heures</item> - <item>6 heures</item> - <item>Jamais</item> - </string-array> - - <string name="pref_title_system_sync_settings">Paramètres de la synchronisation système</string> - - <!-- Example settings for Notifications --> - <string name="pref_header_notifications">Notifications</string> - <string name="pref_title_new_message_notifications">Nouveaux messages de notifications</string> - <string name="pref_title_ringtone">Sonnerie</string> - <string name="pref_ringtone_silent">Muet</string> - <string name="pref_title_vibrate">Vibrer</string> </resources> diff --git a/app/res/values/strings.xml b/app/res/values/strings.xml index dccbe44..8e8cd36 100644 --- a/app/res/values/strings.xml +++ b/app/res/values/strings.xml @@ -3,6 +3,7 @@ <string name="app_name">RepWifi</string> <string name="menu_credits">Info and Credits</string> + <string name="menu_closeapp">Kill RepWifi</string> <string name="scan_networks">Scan for Networks</string> <string name="title_activity_select_network">Select Network</string> <string name="rescan">Repeat Scan</string> @@ -10,7 +11,6 @@ <string name="insert_nets_password">Insert a Password to connect to:</string> <string name="show_password">Show password</string> <string name="title_activity_connect">ConnectActivity</string> - <string name="hello_world">Hello world!</string> <string name="title_activity_show_status">Connection status</string> <string name="back_main">Back to main</string> <string name="disconnect">Disconnect</string> @@ -20,7 +20,7 @@ <string name="delete">Delete network info</string> <string name="manage_networks">Manage Networks</string> <string name="title_activity_credits">Credits</string> - <string name="credit_text">Copyright 2017 Filippo \"Fil\" Bergamo<br/><br/>This app is Free Software.<br/>It\'s licensed under the terms of <a href="https://www.gnu.org/licenses/gpl.txt">GPL v3</a><br/><br/>This app is developed as a contribution to <br/><a href="http://www.replicant.us">The Replicant Project</a><br/><br/><b><u><big>Thank GNUs:</big></u></b><br/><br/><b>Tiberiu - Technoethical</b><br/>for having done the initial job of porting libre WiFi to Replicant 4.2.<br/><br/><b>Wolfgang Wiedmeyer</b><br/>for porting libre WiFi to Replicant 6.0 and for helping with the scripts.<br/><br/>To report on bugs, request features, or any help request, please refer to:<br/><a href="http://redmine.replicant.us/projects/replicant/boards">Replicant\'s Forum</a><br/><br/>Source code is hosted at: <br/><a href="https://git.replicant.us/contrib/Fil/RepWifiApp/">https://git.replicant.us/contrib/Fil/RepWifiApp/</a><br/></string> + <string name="credit_text">Copyright 2017 Filippo \"Fil\" Bergamo<br/><br/>This app is Free Software.<br/>It\'s licensed under the terms of <a href="https://www.gnu.org/licenses/gpl.txt">GPL v3</a><br/><br/>This app is developed as a contribution to <br/><a href="http://www.replicant.us">The Replicant Project</a><br/>To report on bugs, request features, or any help request, please refer to:<br/><a href="http://redmine.replicant.us/projects/replicant/boards">Replicant\'s Forum</a><br/><br/>Source code is hosted at: <br/><a href="https://git.replicant.us/contrib/Fil/RepWifiApp/">https://git.replicant.us/contrib/Fil/RepWifiApp/</a><br/><br/><b><u><big>Thank GNUs:</big></u></b><br/><br/><b>Tiberiu - Technoethical</b><br/>for having done the initial job of porting libre WiFi to Replicant 4.2.<br/><br/><b>Wolfgang Wiedmeyer</b><br/>for porting libre WiFi to Replicant 6.0 and for helping with the scripts.<br/><br/><b>Nicola Spanti</b><br/>for the French translation.<br/><br/><b>Nichlas Severinsen</b><br/>for publishing this app on F-Droid.<br/><br/></string> <string name="menu_config">Settings</string> <string name="msg_interface_not_found">WiFi adapter not found!\nPlease plug in a supported WiFi adapter and retry.</string> <string name="msg_confirm_delete_network">Are you sure you want to delete this network?</string> @@ -38,7 +38,84 @@ <string name="dns2_default">169.239.202.202</string> <string name="receiver_description">RepWifi\'s listener for startup event. Provides auto-start and notification features to RepWifi.</string> <string name="confirm_reset_settings">Are you sure you want to reset all settings to default?</string> + <string name="confirm_exit_app">Are you sure you want to kill RepWifi? This will disconnect you from WiFi.</string> <string name="confirm_kill_backend">Are you sure you want to kill the back-end processes?</string> <string name="summary_kill_backend">Sometimes back-end programs get stuck in inconsistent states.\nClicking this button restores normal behaviour by killing running instances of wpa_supplicant and dhcpcd."</string> + <string name="text_presented_by">Brought to you by:</string> + <string name="title_input_password">Input Password</string> + <string name="msg_password_empty">Password can\'t be empty!</string> + <string name="title_input_ssid">Insert Network\'s parameters</string> + <string name="msg_network_name_empty">Network name can\'t be empty!</string> + <string name="msg_connecting_to">Connecting to </string> + <string name="title_scanning">Scanning...</string> + <string name="msg_scanning_for_nets">Scanning for Networks...</string> + <string name="msg_checking_status">Checking status...</string> + <string name="msg_please_wait">Please wait...</string> + <string name="msg_network_saved">Network saved!</string> + <string name="msg_network_save_fail">FAILED to save network!</string> + <string name="msg_connect_fail">FAILED to connect!</string> + <string name="msg_netinfo_deleted">Network Info deleted!</string> + <string name="msg_netinfo_delete_fail">FAILED to delete Network Info!</string> + <string name="msg_autoconnect_error">An error occurred while trying to auto-connect</string> + <string name="text_netinfo_last_used">Last Used</string> + <string name="text_password">Password</string> + <string name="msg_network_list_fail">Unable to retrieve network list!</string> + <string name="msg_no_network">No network found.</string> + <string name="msg_select_network_connect">Select the network you want to connect to:</string> + <string name="msg_select_network_manage">Select network info to manage:</string> + <string name="msg_log_saved">Logs saved to file</string> + <string name="msg_log_save_fail">Failed to dump logs!</string> + <string name="msg_error_ip_format">ERROR:\nWrong IP format!</string> + <string name="msg_connected_to">Connected to</string> + <string name="text_ip_address">IP Address</string> + <string name="msg_disconnected">Disconnected.</string> + <string name="msg_disconnect_fail">FAILED to disconnect!</string> + <string name="text_status">Status</string> + <string name="msg_no_saved_network">No saved network</string> + <string name="msg_touch_open">Touch to open.</string> + <string name="msg_os_unsupported">UNSUPPORTED OS VERSION\nThe current version of Replicant is not supported by RepWifi.\nPlease upgrade to the latest version as soon as possible!</string> + <string name="title_log_prio">Log priority</string> + <string name="title_dump_logs">Dump logs to file</string> + <string name="title_reset_backend">Reset back-end engine</string> + <string name="title_dns_1">DNS server #1</string> + <string name="title_dns_2">DNS server #2</string> + <string name="summary_dns1">Set the IPv4 address of the primary DNS server.\nIf left blank, RepWifi will try to use the default gateway as a DNS resolver.</string> + <string name="summary_dns2">Set the IPv4 address of the secondary DNS server.\nIf the primary address is blank, this will be ignored.</string> + <string name="title_autoconnect">Enable Autoconnect</string> + <string name="summary_autoconnect">When the WiFi dongle is attached, RepWifi connects automatically to reachable known networks.\n(Experimental).</string> + <string name="title_progbar">Animated progress bar</string> + <string name="summary_progbar">Show an animated progress bar while doing long background tasks.\nKeep it disabled to (hopefully) save some extra power for the WiFi dongle.</string> + <string name="title_start_at_boot">Enable Start at Boot</string> + <string name="summary_start_at_boot">If checked, RepWifi is started automatically on system\'s startup.</string> + <string name="title_restore_default">Restore Defaults</string> + <string name="summary_restore_default">click to restore default settings\n(then return to main screen to apply the reset)</string> + <string name="title_advanced_settings">Advanced & Debug</string> + <string name="title_general_settings">Options</string> + <string name="summary_advanced_settings">set advanced options and debug variables</string> + <string name="summary_general_settings">set general options</string> + <string name="text_use_dhcp">Use DHCP</string> + <string name="text_ipv4_settings">IPv4 settings</string> + <string name="text_static_ip">Static IP</string> + <string name="text_subnet_mask">Subnet Mask</string> + <string name="text_gateway">Gateway</string> + <string name="title_activity_ipv4_settings">Ipv4SettingsActivity</string> + <string name="txt_save_ip_settings">Save IP settings</string> + <string name="txt_back">Back</string> + <string name="msg_invalid_ip">Invalid IP address!</string> + <string name="msg_invalid_netmask">Invalid Subnet Mask!</string> + <string name="msg_invalid_gateway">Invalid Gateway!</string> + <string name="msg_vpn_disconnect_error">ERROR while disconnecting from VPN!</string> + <string name="msg_vpn_disconnect">Disconnected from VPN</string> + <string name="msg_vpn_launched">Launched VPN connection</string> + <string name="msg_vpn_wrong_profile">Invalid profile name!</string> + <string name="title_vpn_settings">VPN settings</string> + <string name="text_vpn_package_missing">Seems like the required VPN app is not installed.\nRepWifi needs "[VPN_EXT_APP]" to be installed, in order to provide VPN features.\nPlease install "[VPN_EXT_APP]" and retry.</string> + <string name="msg_vpn_no_permission">VPN permission denied.\nYou need to grant RepWifi permission to use "[VPN_EXT_APP]" when you are prompted for it.\nRepWifi won\'t be able to start VPN until you do so.</string> + <string name="msg_vpn_connect_error">** ERROR while connecting to VPN **</string> + <string name="title_activity_vpn_settings">VPN Settings</string> + <string name="hello_world">Hello world!</string> + <string name="txt_save">Save</string> + <string name="summary_vpn_settings">Select the name of a VPN profile that you want to be launched automatically when you connect to this network.\nLeave blank to disable automatic VPN connection.\nTo use VPN capability, "[VPN_EXT_APP]" must be installed in the system.</string> + <string name="msg_vpn_no_profile">No profile found.\nPlease add a VPN profile inside [VPN_EXT_APP] before using this feature.</string> </resources>
\ No newline at end of file diff --git a/app/res/values/strings_activity_input_password.xml b/app/res/values/strings_activity_input_password.xml index 4770a51..31b8865 100644 --- a/app/res/values/strings_activity_input_password.xml +++ b/app/res/values/strings_activity_input_password.xml @@ -3,15 +3,6 @@ <string name="title_activity_input_password">Insert passwrod for network</string> <!-- Strings related to login --> - <string name="prompt_email">Email</string> - <string name="prompt_password">Password</string> - <string name="action_sign_in_register"><b>Sign in</b> or register</string> - <string name="action_sign_in_short">Sign in</string> - <string name="menu_forgot_password">Recover lost password</string> - <string name="login_progress_signing_in">Signing in…</string> - <string name="error_invalid_email">This email address is invalid</string> - <string name="error_invalid_password">This password is too short</string> - <string name="error_incorrect_password">This password is incorrect</string> - <string name="error_field_required">This field is required</string> + </resources>
\ No newline at end of file diff --git a/app/res/values/strings_activity_settings.xml b/app/res/values/strings_activity_settings.xml index d7bab93..dfc25ca 100644 --- a/app/res/values/strings_activity_settings.xml +++ b/app/res/values/strings_activity_settings.xml @@ -6,52 +6,9 @@ <!-- Example General settings --> - <string name="pref_header_general">General</string> - <string name="pref_title_social_recommendations">Enable social recommendations</string> - <string name="pref_description_social_recommendations">Recommendations for people to contact based on your message history</string> - <string name="pref_title_display_name">Display name</string> - <string name="pref_default_display_name">John Smith</string> - <string name="pref_title_add_friends_to_messages">Add friends to messages</string> - - <string-array name="pref_example_list_titles"> - <item>Always</item> - <item>When possible</item> - <item>Never</item> - </string-array> - <string-array name="pref_example_list_values"> - <item>1</item> - <item>0</item> - <item>-1</item> - </string-array> <!-- Example settings for Data & Sync --> - <string name="pref_header_data_sync">Data & sync</string> - <string name="pref_title_sync_frequency">Sync frequency</string> - - <string-array name="pref_sync_frequency_titles"> - <item>15 minutes</item> - <item>30 minutes</item> - <item>1 hour</item> - <item>3 hours</item> - <item>6 hours</item> - <item>Never</item> - </string-array> - <string-array name="pref_sync_frequency_values"> - <item>15</item> - <item>30</item> - <item>60</item> - <item>180</item> - <item>360</item> - <item>-1</item> - </string-array> - - <string name="pref_title_system_sync_settings">System sync settings</string> <!-- Example settings for Notifications --> - <string name="pref_header_notifications">Notifications</string> - <string name="pref_title_new_message_notifications">New message notifications</string> - <string name="pref_title_ringtone">Ringtone</string> - <string name="pref_ringtone_silent">Silent</string> - <string name="pref_title_vibrate">Vibrate</string> </resources>
\ No newline at end of file diff --git a/app/res/values/styles.xml b/app/res/values/styles.xml index 18e186b..2a431aa 100644 --- a/app/res/values/styles.xml +++ b/app/res/values/styles.xml @@ -42,7 +42,7 @@ <item name="android:textColor">@color/ThemeLight</item> <item name="android:cacheColorHint">@color/Anthracite</item> </style> - + <style name="RepWifi.BorderlessButton" parent="@android:style/Widget.Holo.Button.Borderless"> <item name="android:textColor">@color/ThemeLight</item> <item name="android:background">@drawable/repwifi_button</item> diff --git a/app/res/xml/debug_settings.xml b/app/res/xml/debug_settings.xml index 8aa09f4..f7be0f0 100644 --- a/app/res/xml/debug_settings.xml +++ b/app/res/xml/debug_settings.xml @@ -6,10 +6,15 @@ android:entries="@array/debug_priority_names" android:entryValues="@array/debug_priority" android:key="debug_priority" - android:title="Log priority" + android:title="@string/title_log_prio" android:divider="@drawable/divider_shape" /> - <Preference android:title="Reset back-end engine" + <Preference android:title="@string/title_dump_logs" + android:key="pref_dump_log" + android:background="@drawable/button_bg" + android:textColor="@color/ThemeLight"/> + + <Preference android:title="@string/title_reset_backend" android:key="pref_kill_backend" android:summary="@string/summary_kill_backend" android:background="@drawable/button_bg" diff --git a/app/res/xml/general_settings.xml b/app/res/xml/general_settings.xml index d836b67..bd9fdf9 100644 --- a/app/res/xml/general_settings.xml +++ b/app/res/xml/general_settings.xml @@ -5,8 +5,8 @@ android:id="@+id/pref_dns1" android:defaultValue="@string/dns1_default" android:key="dns1" - android:summary="Set the IPv4 address of the primary DNS server.\nIf left blank, RepWifi will try to use the default gateway as a DNS resolver." - android:title="DNS server #1" + android:summary="@string/summary_dns1" + android:title="@string/title_dns_1" android:textColor="@color/ThemeLight" android:background="@color/ThemeDark" android:padding="5dp"/> @@ -16,8 +16,8 @@ android:id="@+id/pref_dns2" android:defaultValue="@string/dns2_default" android:key="dns2" - android:summary="Set the IPv4 address of the secondary DNS server.\nIf the primary address is blank, this will be ignored." - android:title="DNS server #2" + android:summary="@string/summary_dns2" + android:title="@string/title_dns_2" android:textColor="@color/ThemeLight" android:background="@color/ThemeDark" android:padding="5dp"/> @@ -26,26 +26,26 @@ android:id="@+id/pref_autoconnect" android:defaultValue="false" android:key="enable_autoconnect" - android:summary="When the WiFi dongle is attached, RepWifi connects automatically to reachable known networks.\n(Experimental)." - android:title="Enable Autoconnect" /> - + android:summary="@string/summary_autoconnect" + android:title="@string/title_autoconnect" /> + <CheckBoxPreference android:id="@+id/pref_progbar" android:defaultValue="true" android:key="enable_progbar" - android:summary="Show an animated progress bar while doing long background tasks.\nKeep it disabled to (hopefully) save some extra power for the WiFi dongle." - android:title="Animated progress bar" /> + android:summary="@string/summary_progbar" + android:title="@string/title_progbar" /> <CheckBoxPreference android:id="@+id/pref_autostart" android:defaultValue="false" android:key="enable_autostart" - android:summary="If checked, RepWifi is started automatically on system's startup." - android:title="Enable Start at Boot" /> + android:summary="@string/summary_start_at_boot" + android:title="@string/title_start_at_boot" /> - <Preference android:title="Restore Defaults" + <Preference android:title="@string/title_restore_default" android:key="pref_restore_default" - android:summary="click to restore default settings\n(then return to main screen to apply the reset)" + android:summary="@string/summary_restore_default" android:background="@drawable/button_bg" android:textColor="@color/ThemeLight" /> diff --git a/app/res/xml/settings_headers.xml b/app/res/xml/settings_headers.xml index 50f7436..d33ae33 100644 --- a/app/res/xml/settings_headers.xml +++ b/app/res/xml/settings_headers.xml @@ -3,12 +3,12 @@ <header android:fragment="fil.libre.repwifiapp.activities.SettingsActivity$GeneralSettingFragment" - android:summary="set general options" - android:title="Options" /> + android:summary="@string/summary_general_settings" + android:title="@string/title_general_settings" /> <header android:fragment="fil.libre.repwifiapp.activities.SettingsActivity$DebugSettingFragment" - android:summary="set advanced options and debug variables" - android:title="Advanced & Debug" /> + android:summary="@string/summary_advanced_settings" + android:title="@string/title_advanced_settings" /> </preference-headers>
\ No newline at end of file diff --git a/app/src/de/blinkt/openvpn/api/APIVpnProfile.aidl b/app/src/de/blinkt/openvpn/api/APIVpnProfile.aidl new file mode 100644 index 0000000..f679965 --- /dev/null +++ b/app/src/de/blinkt/openvpn/api/APIVpnProfile.aidl @@ -0,0 +1,3 @@ +package de.blinkt.openvpn.api; + +parcelable APIVpnProfile; diff --git a/app/src/de/blinkt/openvpn/api/APIVpnProfile.java b/app/src/de/blinkt/openvpn/api/APIVpnProfile.java new file mode 100644 index 0000000..6acbf43 --- /dev/null +++ b/app/src/de/blinkt/openvpn/api/APIVpnProfile.java @@ -0,0 +1,61 @@ +/*
+ * Copyright (c) 2012-2015 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms.
+ * For full terms see the file https://github.com/schwabe/ics-openvpn/blob/master/doc/LICENSE.txt
+ */
+
+package de.blinkt.openvpn.api;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class APIVpnProfile implements Parcelable {
+
+ public final String mUUID;
+ public final String mName;
+ public final boolean mUserEditable;
+ //public final String mProfileCreator;
+
+ public APIVpnProfile(Parcel in) {
+ mUUID = in.readString();
+ mName = in.readString();
+ mUserEditable = in.readInt() != 0;
+ //mProfileCreator = in.readString();
+ }
+
+ public APIVpnProfile(String uuidString, String name, boolean userEditable, String profileCreator) {
+ mUUID = uuidString;
+ mName = name;
+ mUserEditable = userEditable;
+ //mProfileCreator = profileCreator;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mUUID);
+ dest.writeString(mName);
+ if (mUserEditable)
+ dest.writeInt(0);
+ else
+ dest.writeInt(1);
+ //dest.writeString(mProfileCreator);
+ }
+
+ public static final Creator<APIVpnProfile> CREATOR
+ = new Creator<APIVpnProfile>() {
+ public APIVpnProfile createFromParcel(Parcel in) {
+ return new APIVpnProfile(in);
+ }
+
+ public APIVpnProfile[] newArray(int size) {
+ return new APIVpnProfile[size];
+ }
+ };
+
+
+}
diff --git a/app/src/de/blinkt/openvpn/api/DO_NOT_RENAME b/app/src/de/blinkt/openvpn/api/DO_NOT_RENAME new file mode 100644 index 0000000..a7b3fe8 --- /dev/null +++ b/app/src/de/blinkt/openvpn/api/DO_NOT_RENAME @@ -0,0 +1 @@ +If you create your own remote application remember that these classes are the remote API of ics-openvpn and should be kept as de.blinkt.openvpn.api.
\ No newline at end of file diff --git a/app/src/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl b/app/src/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl new file mode 100644 index 0000000..273a004 --- /dev/null +++ b/app/src/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl @@ -0,0 +1,66 @@ +// IOpenVPNAPIService.aidl
+package de.blinkt.openvpn.api;
+
+import de.blinkt.openvpn.api.APIVpnProfile;
+import de.blinkt.openvpn.api.IOpenVPNStatusCallback;
+
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+
+interface IOpenVPNAPIService {
+ List<APIVpnProfile> getProfiles();
+
+ void startProfile (String profileUUID);
+
+ /** Use a profile with all certificates etc. embedded,
+ * old version which does not return the UUID of the addded profile, see
+ * below for a version that return the UUID on add */
+ boolean addVPNProfile (String name, String config);
+
+ /** start a profile using a config as inline string. Make sure that all needed data is inlined,
+ * e.g., using <ca>...</ca> or <auth-user-data>...</auth-user-data>
+ * See the OpenVPN manual page for more on inlining files */
+ void startVPN (String inlineconfig);
+
+ /** This permission framework is used to avoid confused deputy style attack to the VPN
+ * calling this will give null if the app is allowed to use the external API and an Intent
+ * that can be launched to request permissions otherwise */
+ Intent prepare (String packagename);
+
+ /** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
+ * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
+ * to let OpenVPN for Android request the permission */
+ Intent prepareVPNService ();
+
+ /* Disconnect the VPN */
+ void disconnect();
+
+ /* Pause the VPN (same as using the pause feature in the notifcation bar) */
+ void pause();
+
+ /* Resume the VPN (same as using the pause feature in the notifcation bar) */
+ void resume();
+
+ /**
+ * Registers to receive OpenVPN Status Updates
+ */
+ void registerStatusCallback(IOpenVPNStatusCallback cb);
+
+ /**
+ * Remove a previously registered callback interface.
+ */
+ void unregisterStatusCallback(IOpenVPNStatusCallback cb);
+
+ /** Remove a profile by UUID */
+ void removeProfile (String profileUUID);
+
+ /** Request a socket to be protected as a VPN socket would be. Useful for creating
+ * a helper socket for an app controlling OpenVPN
+ * Before calling this function you should make sure OpenVPN for Android may actually
+ * this function by checking if prepareVPNService returns null; */
+ boolean protectSocket(in ParcelFileDescriptor fd);
+
+
+ /** Use a profile with all certificates etc. embedded */
+ APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config);
+}
\ No newline at end of file diff --git a/app/src/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl b/app/src/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl new file mode 100644 index 0000000..1dfa138 --- /dev/null +++ b/app/src/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl @@ -0,0 +1,13 @@ +package de.blinkt.openvpn.api;
+
+/**
+ * Example of a callback interface used by IRemoteService to send
+ * synchronous notifications back to its clients. Note that this is a
+ * one-way interface so the server does not block waiting for the client.
+ */
+oneway interface IOpenVPNStatusCallback {
+ /**
+ * Called when the service has a new status for you.
+ */
+ void newStatus(String uuid, String state, String message, String level);
+}
diff --git a/app/src/fil/libre/repwifiapp/ActivityLauncher.java b/app/src/fil/libre/repwifiapp/ActivityLauncher.java index 00a8d50..5e9c31d 100644 --- a/app/src/fil/libre/repwifiapp/ActivityLauncher.java +++ b/app/src/fil/libre/repwifiapp/ActivityLauncher.java @@ -1,3 +1,23 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + package fil.libre.repwifiapp; import android.app.Activity; @@ -5,10 +25,12 @@ import android.content.Intent; import android.widget.Toast; import fil.libre.repwifiapp.activities.InputPasswordActivity; import fil.libre.repwifiapp.activities.InputSsidActivity; +import fil.libre.repwifiapp.activities.Ipv4SettingsActivity; import fil.libre.repwifiapp.activities.LongTaskActivity; import fil.libre.repwifiapp.activities.NetworkDetailsActivity; import fil.libre.repwifiapp.activities.SelectNetworkActivity; import fil.libre.repwifiapp.activities.ShowStatusActivity; +import fil.libre.repwifiapp.activities.VpnSettingsActivity; import fil.libre.repwifiapp.helpers.AccessPointInfo; import fil.libre.repwifiapp.helpers.ConnectionStatus; import fil.libre.repwifiapp.helpers.NetworkManager; @@ -39,6 +61,7 @@ public class ActivityLauncher { public static final int CONNECT_HIDDEN = 10; public static final int USB_ATTACHED = 11; public static final int USB_DETACHED = 12; + public static final int VPN_PERMISSION = 13; } @@ -59,7 +82,7 @@ public class ActivityLauncher { } public void launchLongTaskActivityConnect(AccessPointInfo info) { - + Intent intent = new Intent(currentContext, LongTaskActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.putExtra(ActivityLauncher.EXTRA_REQCODE, RequestCode.CONNECT); @@ -102,7 +125,7 @@ public class ActivityLauncher { nets = manager.getKnownNetworks(); if (nets == null || nets.length == 0) { - Toast toast = Toast.makeText(currentContext, "No saved network", Toast.LENGTH_LONG); + Toast toast = Toast.makeText(currentContext, Commons.msgNoSavedNetwork, Toast.LENGTH_LONG); toast.show(); return; } @@ -130,6 +153,24 @@ public class ActivityLauncher { currentContext.startActivityForResult(intent, RequestCode.DETAILS_SHOW); } + + public void launchIpSettingsActivity(AccessPointInfo info) { + + Intent intent = new Intent(currentContext, Ipv4SettingsActivity.class); + // intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.putExtra(EXTRA_APINFO, info); + currentContext.startActivity(intent); + + } + + public void launchVpnSettingsActivity(AccessPointInfo info) { + + Intent intent = new Intent(currentContext, VpnSettingsActivity.class); + // intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.putExtra(EXTRA_APINFO, info); + currentContext.startActivity(intent); + + } public void launchInputSsidActivity() { @@ -139,5 +180,6 @@ public class ActivityLauncher { currentContext.startActivityForResult(intent, RequestCode.CONNECT_HIDDEN); } + } diff --git a/app/src/fil/libre/repwifiapp/Commons.java b/app/src/fil/libre/repwifiapp/Commons.java index 200381f..1603a76 100644 --- a/app/src/fil/libre/repwifiapp/Commons.java +++ b/app/src/fil/libre/repwifiapp/Commons.java @@ -20,6 +20,12 @@ package fil.libre.repwifiapp; +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; +import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; @@ -30,39 +36,33 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.os.Environment; import android.preference.PreferenceManager; import fil.libre.repwifiapp.activities.MainActivity; import fil.libre.repwifiapp.helpers.ConnectionStatus; +import fil.libre.repwifiapp.helpers.Engine; import fil.libre.repwifiapp.helpers.Engine6p0; import fil.libre.repwifiapp.helpers.IEngine; import fil.libre.repwifiapp.helpers.NetworkManager; import fil.libre.repwifiapp.helpers.Utils; +import fil.libre.repwifiapp.helpers.WpaCli; +import fil.libre.repwifiapp.helpers.WpaSupplicant; public abstract class Commons { private static Context currentContext; - public Context getContext() { + public static Context getContext() { return currentContext; } - // ------------- Enviromnet Constants ----------------- + // ------------- Environment Constants ----------------- public static final int EXCOD_ROOT_DISABLED = 255; public static final int EXCOD_ROOT_DENIED = 1; public static final int WAIT_ON_USB_ATTACHED = 1500; + public static final int WAIT_FOR_GATEWAY = 4000; public static final String BSSID_NOT_AVAILABLE = "[BSSID-NOT-AVAILABLE]"; - public static final String v4p2 = "4.2"; public static final String v6p0 = "6.0"; - public static final String SCAN_FILE_HDR = "bssid / frequency / signal level / flags / ssid"; - public static final String INTERFACE_NAME = "wlan0"; - public static final String WORKDIR = "/data/misc/wifi"; - public static final String PID_FILE = WORKDIR + "/pidfile"; - public static final String SOCKET_DIR = WORKDIR + "/sockets/"; - public static final String SOFTAP_FILE = WORKDIR + "/softap.conf"; - public static final String P2P_CONF = WORKDIR + "/p2p_supplicant.conf"; - public static final String WPA_CONF = WORKDIR + "/wpa_supplicant.conf"; - public static final String ENTROPY_FILE = WORKDIR + "/entropy.bin"; - public static final String OVERLAY_FILE = "/system/etc/wifi/wpa_supplicant_overlay.conf"; // --------------------------------------------- // ------------- Shared Engines ----------------------- @@ -76,12 +76,45 @@ public abstract class Commons { public static int colorBlack; public static String dns1Default = ""; public static String dns2Default = ""; + private static String APP_DATA_FOLDER; + public static String msgNoSavedNetwork; + + public static String getNetworkStorageFile() { + if (APP_DATA_FOLDER == null) { + return null; + } else { + return APP_DATA_FOLDER + "/repwifi_storage.conf"; + } + } + + @SuppressLint("SimpleDateFormat") + public static String getLogDumpFile() { + + File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + if (f == null || !f.exists()) { + return null; + } + + String basefolder; + try { + basefolder = f.getCanonicalPath(); + } catch (Exception e) { + Utils.logError("Exception while resolving canonical path for log dump file.", e); + return null; + } + + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss", Locale.getDefault()); + String ts = dateFormat.format(Calendar.getInstance().getTime()); + return basefolder + "/repwifi_log_dump." + ts + ".log"; + } + + // -------------------------------------------------------- private static final int NOTIFICATION_ID = 1; public static void updateNotification(Context context) { - ConnectionStatus status = connectionEngine.getConnectionStatus(); + ConnectionStatus status = WpaCli.getConnectionStatus(); Notification.Builder builder = new Notification.Builder(context); @@ -104,7 +137,7 @@ public abstract class Commons { builder.setSmallIcon(iconId); builder.setContentTitle(msg); - builder.setContentText("Touch to open."); + builder.setContentText(currentContext.getString(R.string.msg_touch_open)); Notification n = builder.build(); n.flags |= Notification.FLAG_NO_CLEAR; @@ -124,12 +157,13 @@ public abstract class Commons { AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context, R.style.Theme_RepWifiDialogTheme); dlgAlert.setMessage(msg); - dlgAlert.setPositiveButton("OK", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - return; - } - }); + dlgAlert.setPositiveButton(currentContext.getString(android.R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + return; + } + }); dlgAlert.setCancelable(false); AlertDialog diag = dlgAlert.create(); @@ -180,9 +214,8 @@ public abstract class Commons { if (silent) { - if (connectionEngine != null) { - connectionEngine.killBackEndProcesses(); - } + Engine.killDhcpcd(); + WpaSupplicant.kill(); } else { @@ -252,55 +285,6 @@ public abstract class Commons { // ---------------------------------------------------- - // ----------------- Application Files -------------------- - private static String APP_DATA_FOLDER; - - public static String getNetworkStorageFile() { - if (APP_DATA_FOLDER == null) { - return null; - } else { - return APP_DATA_FOLDER + "/repwifi_storage.conf"; - } - } - - public static String getTempFile() { - return APP_DATA_FOLDER + "/file.tmp"; - } - - public static String getScriptScan() { - return APP_DATA_FOLDER + "/scan_app.sh"; - } - - public static String getScriptScanRes() { - return APP_DATA_FOLDER + "/get_scan_results_app.sh"; - } - - public static String getScriptDhcpcd() { - return APP_DATA_FOLDER + "/run_dhcpcd.sh"; - } - - public static String getOldSelectScript() { - return WORKDIR + "/select_network.sh"; - } - - public static String getScanFile() { - return APP_DATA_FOLDER + "/scanres.txt"; - } - - public static String getStatusFile() { - return APP_DATA_FOLDER + "/tmpStatus"; - } - - public static String getGwFile() { - return APP_DATA_FOLDER + "/gw.txt"; - } - - public static String getTempOutFile() { - return APP_DATA_FOLDER + "/tmpout.txt"; - } - - // -------------------------------------------------------- - // ----------- Initialization methods --------------------------- public static boolean init(Context context) { @@ -310,6 +294,8 @@ public abstract class Commons { colorThemeDark = currentContext.getResources().getColor(R.color.ThemeDark); colorThemeLight = currentContext.getResources().getColor(R.color.ThemeLight); + msgNoSavedNetwork = currentContext.getResources().getString( + R.string.msg_no_saved_network); colorBlack = currentContext.getResources().getColor(R.color.black); APP_DATA_FOLDER = currentContext.getExternalFilesDir(null).getAbsolutePath(); dns1Default = currentContext.getResources().getString(R.string.dns1_default); @@ -333,7 +319,7 @@ public abstract class Commons { String vers = android.os.Build.VERSION.RELEASE; if (!vers.startsWith(Commons.v6p0)) { - showMessage("UNSUPPORTED OS VERSION\nThe current version of Replicant is not supported by RepWifi.\nPlease upgrade to the latest version as soon as possible!"); + showMessage(currentContext.getString(R.string.msg_os_unsupported)); } } diff --git a/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java b/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java index 3f507ec..ba26bb3 100644 --- a/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java +++ b/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java @@ -7,7 +7,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.util.Log; public class RepWifiIntentReceiver extends BroadcastReceiver { @@ -16,11 +15,9 @@ public class RepWifiIntentReceiver extends BroadcastReceiver { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context .getApplicationContext()); if (!prefs.getBoolean("enable_autostart", false)) { - Log.d("RepWifi", "autostart is false"); return; } - Log.d("RepWifi", "Autostart is true"); String a = intent.getAction(); if (a.equals(Intent.ACTION_BOOT_COMPLETED) || a.equals(Intent.ACTION_REBOOT)) { diff --git a/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java index 6f04d1c..32922c6 100644 --- a/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java @@ -49,7 +49,7 @@ public class InputPasswordActivity extends Activity implements OnCheckedChangeLi CheckBox c = (CheckBox) findViewById(R.id.chk_show_pass); c.setOnCheckedChangeListener(this); - setTitle("Input password"); + setTitle(getResources().getString(R.string.title_input_password)); TextView v = (TextView) findViewById(R.id.txt_insert_pass); @@ -81,7 +81,7 @@ public class InputPasswordActivity extends Activity implements OnCheckedChangeLi String pass = txpass.getText().toString(); if (pass.length() == 0) { - Commons.showMessage("Password can't be empty!", this); + Commons.showMessage(getString(R.string.msg_password_empty), this); } this.apinfo.setPassword(pass); diff --git a/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java b/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java index 4f3f74c..8b7c60c 100644 --- a/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java @@ -39,7 +39,7 @@ public class InputSsidActivity extends Activity { super.onCreate(icicle); setContentView(R.layout.activity_input_ssid); - setTitle("Insert Network's parameters"); + setTitle(getString(R.string.title_input_ssid)); } @@ -85,7 +85,7 @@ public class InputSsidActivity extends Activity { String ssid = txssid.getText().toString(); if (ssid.length() == 0) { - Commons.showMessage("Network name can't be empty!", this); + Commons.showMessage(getString(R.string.msg_network_name_empty), this); return; } diff --git a/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java new file mode 100644 index 0000000..1f15252 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java @@ -0,0 +1,181 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + +package fil.libre.repwifiapp.activities; + +import fil.libre.repwifiapp.ActivityLauncher; +import fil.libre.repwifiapp.Commons; +import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.helpers.AccessPointInfo; +import fil.libre.repwifiapp.helpers.DhcpSettings; +import android.nfc.FormatException; +import android.os.Bundle; +import android.app.Activity; +import android.content.Intent; +import android.view.Menu; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.CompoundButton.OnCheckedChangeListener; + +public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeListener { + + private AccessPointInfo currentNetwork; + private DhcpSettings currentSettings; + + private EditText txtIp; + private EditText txtGw; + private EditText txtMask; + private CheckBox chkDhcp; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_ipv4_settings); + + chkDhcp = (CheckBox) findViewById(R.id.chk_use_dhcp); + txtIp = (EditText) findViewById(R.id.txt_static_ip); + txtMask = (EditText) findViewById(R.id.txt_netmask); + txtGw = (EditText) findViewById(R.id.txt_gateway); + + chkDhcp.setOnCheckedChangeListener(this); + + Intent intent = getIntent(); + if (!intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) { + this.setResult(RESULT_CANCELED); + this.finish(); + return; + } + + this.currentNetwork = (AccessPointInfo) intent.getExtras().getSerializable( + ActivityLauncher.EXTRA_APINFO); + if (this.currentNetwork == null) { + this.setResult(RESULT_CANCELED); + this.finish(); + return; + } + + this.currentNetwork = Commons.storage.getSavedNetwork(currentNetwork); + + loadNetwork(); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + // getMenuInflater().inflate(R.menu.activity_manage_networks, menu); + return true; + } + + private void loadNetwork() { + + setTitle(this.currentNetwork.getSsid()); + currentSettings = this.currentNetwork.getDhcpConfiguration(); + loadSettings(); + + } + + private void loadSettings() { + + if (currentSettings.useDhcp) { + + chkDhcp.setChecked(true); + + txtIp.setText(""); + txtIp.setEnabled(false); + + txtMask.setText(""); + txtMask.setEnabled(false); + + txtGw.setText(""); + txtGw.setEnabled(false); + + } else { + chkDhcp.setChecked(false); + + txtIp.setText(currentSettings.getStaticIP()); + txtIp.setEnabled(true); + + txtMask.setText(currentSettings.getSubnetMaskString()); + txtMask.setEnabled(true); + + txtGw.setText(currentSettings.getDefaultGateway()); + txtGw.setEnabled(true); + } + + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + + if (buttonView == findViewById(R.id.chk_use_dhcp)) { + currentSettings.useDhcp = isChecked; + loadSettings(); + + } + + } + + public void btnSaveClick(View v) throws FormatException { + + if (chkDhcp.isChecked()) { + currentSettings.useDhcp = true; + + } else { + + String ip = txtIp.getText().toString(); + String mask = txtMask.getText().toString(); + String gw = txtGw.getText().toString(); + + if (!DhcpSettings.isValidAddress(ip)) { + Commons.showMessage(getString(R.string.msg_invalid_ip),this); + return; + } + + if (!DhcpSettings.isValidMaks(mask)) { + Commons.showMessage(getString(R.string.msg_invalid_netmask),this); + return; + } + + if (!DhcpSettings.isValidAddress(gw)) { + Commons.showMessage(getString(R.string.msg_invalid_gateway),this); + return; + } + + currentSettings = new DhcpSettings(chkDhcp.isChecked(), ip, mask, gw); + + } + + currentNetwork.setDhcpConfiguration(currentSettings); + if (Commons.storage.save(currentNetwork)) { + Commons.showMessage(getString(R.string.msg_network_saved),this); + } else { + Commons.showMessage(getString(R.string.msg_network_save_fail),this); + } + + } + + public void btnBackClick(View v) { + finish(); + } + +} diff --git a/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java index e0b4184..a5292d2 100644 --- a/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java @@ -1,3 +1,24 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + + package fil.libre.repwifiapp.activities; import fil.libre.repwifiapp.ActivityLauncher; @@ -99,21 +120,21 @@ public class LongTaskActivity extends Activity { // Extract AccessPointInfo input = intent.getExtras().getSerializable(ActivityLauncher.EXTRA_APINFO); currentNetwork = (AccessPointInfo) input; - setTitle("Connecting to " + currentNetwork.getSsid() + "..."); - setMessage("Connecting to " + currentNetwork.getSsid() + "..."); + setTitle(getString(R.string.msg_connecting_to) + " " + currentNetwork.getSsid() + "..."); + setMessage(getString(R.string.msg_connecting_to) + " " + currentNetwork.getSsid() + "..."); break; case ActivityLauncher.RequestCode.NETWORKS_GET: - setTitle("Scanning..."); - setMessage("Scanning for Networks..."); + setTitle(getString(R.string.title_scanning)); + setMessage(getString(R.string.msg_scanning_for_nets)); case ActivityLauncher.RequestCode.STATUS_GET: - setTitle("Checking status..."); - setMessage("Checking status..."); + setTitle(getString(R.string.msg_checking_status)); + setMessage(getString(R.string.msg_checking_status)); default: - setTitle("Please wait..."); - setMessage("Please wait..."); + setTitle(getString(R.string.msg_please_wait)); + setMessage(getString(R.string.msg_please_wait)); break; } diff --git a/app/src/fil/libre/repwifiapp/activities/MainActivity.java b/app/src/fil/libre/repwifiapp/activities/MainActivity.java index 6e667bf..7a22416 100644 --- a/app/src/fil/libre/repwifiapp/activities/MainActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/MainActivity.java @@ -20,7 +20,6 @@ package fil.libre.repwifiapp.activities; -import java.io.IOException; import java.net.SocketException; import fil.libre.repwifiapp.ActivityLauncher; import fil.libre.repwifiapp.Commons; @@ -29,8 +28,10 @@ import fil.libre.repwifiapp.ActivityLauncher.RequestCode; import fil.libre.repwifiapp.helpers.AccessPointInfo; import fil.libre.repwifiapp.helpers.ConnectionStatus; import fil.libre.repwifiapp.helpers.NetworkManager; +import fil.libre.repwifiapp.helpers.OpenVpnManager; import fil.libre.repwifiapp.helpers.RootCommand; import fil.libre.repwifiapp.helpers.Utils; +import fil.libre.repwifiapp.helpers.WpaSupplicant; import android.os.Bundle; import android.content.BroadcastReceiver; import android.content.Context; @@ -59,8 +60,16 @@ public class MainActivity extends MenuEnabledActivity { return; } + if (! Commons.storage.updateStorageVersion()){ + Utils.logError("Failed to convert storage file to new version!"); + } + setImage(); setUsbDeviceMonitor(); + setVersionOnTitle(); + + OpenVpnManager.initialize(this); + } @Override @@ -149,11 +158,6 @@ public class MainActivity extends MenuEnabledActivity { handleFinishedConnecting(conres, i); break; - case RequestCode.STATUS_GET: - ConnectionStatus status = (ConnectionStatus) intent.getExtras().getSerializable( - ActivityLauncher.EXTRA_CONSTATUS); - handleResultGetStatus(status); - break; case RequestCode.NETWORKS_GET: AccessPointInfo[] nets = (AccessPointInfo[]) intent.getExtras().getSerializable( @@ -182,6 +186,7 @@ public class MainActivity extends MenuEnabledActivity { } break; + default: break; @@ -190,6 +195,23 @@ public class MainActivity extends MenuEnabledActivity { } + private void setVersionOnTitle() { + + try { + + String vers = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + if (vers == null) { + return; + } + + setTitle(getTitle() + " - v." + vers); + + } catch (Exception e) { + Utils.logError("Error while setting version on MainActivity's title.", e); + } + + } + private void setImage() { ImageView img = (ImageView) findViewById(R.id.img_logo); @@ -197,7 +219,7 @@ public class MainActivity extends MenuEnabledActivity { try { Drawable d = Drawable.createFromStream(getAssets().open("repwifi-logo-0.png"), null); img.setImageDrawable(d); - } catch (IOException e) { + } catch (Exception e) { Utils.logError("Error while loading logo image", e); } @@ -224,6 +246,7 @@ public class MainActivity extends MenuEnabledActivity { } private boolean checkConditions() { + return (checkRootEnabled() && checkInterface(true)); } @@ -233,7 +256,7 @@ public class MainActivity extends MenuEnabledActivity { String msg = ""; try { - res = Commons.connectionEngine.isInterfaceAvailable(Commons.INTERFACE_NAME); + res = Commons.connectionEngine.isInterfaceAvailable(WpaSupplicant.INTERFACE_NAME); } catch (SocketException e) { Utils.logError("SocketException during isInterfaceAvailable()", e); msg = "Error while retrieving interface list!"; @@ -258,7 +281,7 @@ public class MainActivity extends MenuEnabledActivity { int excode = -1; try { - excode = su.execute(); + excode = su.testRootAccess(); } catch (Exception e) { Utils.logError("Error while trying to get first Super User access.", e); excode = -1; @@ -304,7 +327,7 @@ public class MainActivity extends MenuEnabledActivity { if (i.needsPassword()) { - // try to fetch network's password from storage + // try to fetch network's configuration from storage AccessPointInfo fromStorage = Commons.storage.getSavedNetwork(i); if (fromStorage == null) { @@ -327,12 +350,6 @@ public class MainActivity extends MenuEnabledActivity { launcher.launchLongTaskActivityConnect(i); } - private void handleResultGetStatus(ConnectionStatus status) { - if (status != null && status.isConnected()) { - launcher.launchStatusActivity(status); - } - } - private void handleFinishedConnecting(boolean connectionResult, AccessPointInfo info) { if (connectionResult && info.needsPassword()) { @@ -345,13 +362,13 @@ public class MainActivity extends MenuEnabledActivity { // Save network if (Commons.storage.save(info)) { - Toast toast2 = Toast.makeText(getApplicationContext(), "Network Saved!", - Toast.LENGTH_LONG); + Toast toast2 = Toast.makeText(getApplicationContext(), + getString(R.string.msg_network_saved), Toast.LENGTH_LONG); toast2.show(); } else { - Toast toast2 = Toast.makeText(getApplicationContext(), "FAILED to save network!", - Toast.LENGTH_LONG); + Toast toast2 = Toast.makeText(getApplicationContext(), + getString(R.string.msg_network_save_fail), Toast.LENGTH_LONG); toast2.show(); } @@ -360,8 +377,8 @@ public class MainActivity extends MenuEnabledActivity { } else { // alert that connection failed - Toast toast = Toast.makeText(getApplicationContext(), "FAILED to connect!", - Toast.LENGTH_LONG); + Toast toast = Toast.makeText(getApplicationContext(), + getString(R.string.msg_connect_fail), Toast.LENGTH_LONG); toast.show(); } } @@ -371,9 +388,9 @@ public class MainActivity extends MenuEnabledActivity { NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile()); String msg = ""; if (manager.remove(info)) { - msg = "Network info deleted!"; + msg = getString(R.string.msg_netinfo_deleted); } else { - msg = "FAILED to delete network info!"; + msg = getString(R.string.msg_netinfo_delete_fail); } Toast toast = Toast.makeText(this, msg, Toast.LENGTH_LONG); @@ -437,7 +454,7 @@ public class MainActivity extends MenuEnabledActivity { } catch (Exception e) { Utils.logError("Error while autoconnecting", e); - Commons.showMessage("An error occured while trying to auto-connect", this); + Commons.showMessage(getString(R.string.msg_autoconnect_error), this); } } diff --git a/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java b/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java index 0edfcf0..f5c8516 100644 --- a/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java @@ -1,20 +1,60 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + package fil.libre.repwifiapp.activities; +import java.lang.reflect.Field; +import fil.libre.repwifiapp.Commons; import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.helpers.RootCommand; import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; +import android.view.ViewConfiguration; public class MenuEnabledActivity extends Activity { @Override + protected void onCreate(android.os.Bundle savedInstanceState) { + try { + ViewConfiguration config = ViewConfiguration.get(this); + Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); + if (menuKeyField != null) { + menuKeyField.setAccessible(true); + menuKeyField.setBoolean(config, false); + } + } catch (Exception ignored) { + } + super.onCreate(savedInstanceState); + }; + + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } - + @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection @@ -27,6 +67,10 @@ public class MenuEnabledActivity extends Activity { case R.id.menu_config: launchSettingsActivity(); break; + + case R.id.menu_btn_closeapp: + CloseApplication(false); + break; default: break; @@ -46,4 +90,46 @@ public class MenuEnabledActivity extends Activity { // intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity(intent); } + + protected void CloseApplication(boolean silent) { + + if (silent) { + + Commons.connectionEngine.disconnect(); + Commons.killBackEnd(this, true); + super.onDestroy(); + RootCommand.executeRootCmd("am force-stop " + getPackageName()); + + } else { + + String msg = getString(R.string.confirm_exit_app); + AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this, + R.style.Theme_RepWifiDialogTheme); + dlgAlert.setMessage(msg); + dlgAlert.setPositiveButton(this.getString(android.R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + CloseApplication(true); + return; + } + }); + dlgAlert.setNegativeButton(getString(android.R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + return; + } + }); + + dlgAlert.setCancelable(false); + AlertDialog diag = dlgAlert.create(); + + diag.show(); + return; + + } + + } + } diff --git a/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java index 325d546..f2a8944 100644 --- a/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java @@ -22,6 +22,7 @@ package fil.libre.repwifiapp.activities; import java.util.Date; import fil.libre.repwifiapp.ActivityLauncher; +import fil.libre.repwifiapp.Commons; import fil.libre.repwifiapp.R; import fil.libre.repwifiapp.helpers.AccessPointInfo; import android.os.Bundle; @@ -69,6 +70,12 @@ public class NetworkDetailsActivity extends Activity implements OnCheckedChangeL } @Override + protected void onStart() { + super.onStart(); + currentNetwork = Commons.storage.getSavedNetwork(currentNetwork); + }; + + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. // getMenuInflater().inflate(R.menu.activity_manage_networks, menu); @@ -88,17 +95,26 @@ public class NetworkDetailsActivity extends Activity implements OnCheckedChangeL if (lastused > 0) { Date ts = new Date(lastused); String formstring = "dd-MMM-yyyy kk:mm:ss"; - v.append("\nLast Used: " + DateFormat.format(formstring, ts)); + v.append("\n" + getString(R.string.text_netinfo_last_used) + ": " + + DateFormat.format(formstring, ts)); } if (showPassword) { - v.append("\n\nPassword:\n" + this.currentNetwork.getPassword()); + v.append("\n\n" + getString(R.string.text_password) + ":\n" + this.currentNetwork.getPassword()); } else { v.append("\n\n\n"); } } + public void btnIpSettingsClick(View v){ + new ActivityLauncher(this).launchIpSettingsActivity(currentNetwork); + } + + public void btnVpnSettingsClick(View v){ + new ActivityLauncher(this).launchVpnSettingsActivity(currentNetwork); + } + public void btnDeleteClick(View v) { String msg = getResources().getString(R.string.msg_confirm_delete_network); diff --git a/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java index 341fb68..51baed8 100644 --- a/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java @@ -48,7 +48,7 @@ public class SelectNetworkActivity extends Activity implements OnClickListener { super.onCreate(savedInstanceState); setContentView(R.layout.activity_select_network); - setTitle("Select network"); + setTitle(getString(R.string.title_activity_select_network)); getNetworks(); @@ -135,17 +135,17 @@ public class SelectNetworkActivity extends Activity implements OnClickListener { if (info == null) { Utils.logError("Unable to retrieve network list!"); - writeOut("Unable to retrieve network list!"); + writeOut(getString(R.string.msg_network_list_fail)); return; } if (info.length == 0) { - writeOut("No network found."); + writeOut(getString(R.string.msg_no_network)); toggleBtnRescan(true); return; } - writeOut("Select the network you want to connect to:"); + writeOut(getString(R.string.msg_select_network_connect)); toggleBtnRescan(false); for (AccessPointInfo i : info) { @@ -162,7 +162,7 @@ public class SelectNetworkActivity extends Activity implements OnClickListener { return; } - writeOut("Select network info to manage:"); + writeOut(getString(R.string.msg_select_network_manage)); toggleBtnRescan(false); for (AccessPointInfo i : info) { diff --git a/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java index 6f14748..36e0e1f 100644 --- a/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java @@ -1,9 +1,31 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + + package fil.libre.repwifiapp.activities; import org.apache.http.conn.util.InetAddressUtils; import java.util.List; import fil.libre.repwifiapp.Commons; import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.helpers.Utils; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.Preference; @@ -31,6 +53,7 @@ public class SettingsActivity extends PreferenceActivity { addPreferencesFromResource(R.xml.debug_settings); setConfirmKillBackend(); + setDumpFileClick(); } @@ -48,6 +71,24 @@ public class SettingsActivity extends PreferenceActivity { } + private void setDumpFileClick() { + Preference pref = getPreferenceScreen().findPreference("pref_dump_log"); + pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + + @Override + public boolean onPreferenceClick(Preference p) { + if (Utils.dumpLogcatToFile(Commons.getLogDumpFile())) { + Commons.showMessage(getString(R.string.msg_log_saved) + ": \n" + Commons.getLogDumpFile(), + getActivity()); + + } else { + Commons.showMessage(getString(R.string.msg_log_save_fail), getActivity()); + } + return true; + } + }); + } + } public static class GeneralSettingFragment extends PreferenceFragment { @@ -76,7 +117,7 @@ public class SettingsActivity extends PreferenceActivity { || InetAddressUtils.isIPv4Address((String) newValue)) { return true; } else { - Commons.showMessage("ERROR:\nWrong IP format!", getActivity()); + Commons.showMessage(getString(R.string.msg_error_ip_format), getActivity()); return false; } } diff --git a/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java index 0fb8992..21bfc4c 100644 --- a/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java @@ -23,9 +23,14 @@ package fil.libre.repwifiapp.activities; import fil.libre.repwifiapp.ActivityLauncher; import fil.libre.repwifiapp.Commons; import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.ActivityLauncher.RequestCode; +import fil.libre.repwifiapp.helpers.AccessPointInfo; import fil.libre.repwifiapp.helpers.ConnectionStatus; +import fil.libre.repwifiapp.helpers.OpenVpnManager; import fil.libre.repwifiapp.helpers.Utils; +import android.content.Intent; import android.os.Bundle; +import android.os.RemoteException; import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -35,6 +40,8 @@ public class ShowStatusActivity extends MenuEnabledActivity { private ConnectionStatus status; + // private AccessPointInfo info; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -45,14 +52,45 @@ public class ShowStatusActivity extends MenuEnabledActivity { ActivityLauncher.EXTRA_CONSTATUS); } - showStatus(false); + try { + showStatus(false); + } catch (Exception e) { + Utils.logError("Exception on showStatus", e); + } } @Override public void onRestart() { super.onRestart(); - showStatus(true); + try { + showStatus(true); + } catch (Exception e) { + Utils.logError("Exception on showStatus", e); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + + switch (requestCode) { + + case RequestCode.VPN_PERMISSION: + + if (resultCode == RESULT_OK) { + endLaunchVpn(true); + } else { + endLaunchVpn(false); + } + + break; + + default: + + break; + + } + } private void setMessage(String msg) { @@ -60,7 +98,7 @@ public class ShowStatusActivity extends MenuEnabledActivity { view.setText(msg); } - private void showStatus(boolean refresh) { + private void showStatus(boolean refresh) throws Exception { if (refresh || status == null) { this.status = Commons.connectionEngine.getConnectionStatus(); @@ -71,12 +109,14 @@ public class ShowStatusActivity extends MenuEnabledActivity { } else if (this.status.isConnected()) { Utils.logDebug("StatusActivity isConnected,showing buttons"); - setMessage("Connected to " + status.SSID + "\n\n" + "IP Address: " + status.IP + "\n"); + setMessage(getString(R.string.msg_connected_to) + " " + status.SSID + "\n\n" + + getString(R.string.text_ip_address) + ": " + status.IP + "\n"); toggleBtnDisconnect(true); - + beginLauncVpn(); + } else { Utils.logDebug("StatusActivity status Else"); - setMessage("Status:\n" + status.status); + setMessage(getString(R.string.text_status) + ":\n" + status.status); toggleBtnDisconnect(false); } @@ -103,21 +143,144 @@ public class ShowStatusActivity extends MenuEnabledActivity { public void onBtnDisconnectClick(View v) { + disconnectVpn(); + boolean res = Commons.connectionEngine.disconnect(); String msg = ""; if (res) { - msg = "Disconnected."; + msg = getString(R.string.msg_disconnected); } else { - msg = "FAILED to disconnect!"; + msg = getString(R.string.msg_disconnect_fail); } Toast toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT); toast.show(); - showStatus(true); + try { + showStatus(true); + } catch (Exception e) { + Utils.logError("Exception on showStatus", e); + } + + } + + private void disconnectVpn() { + + if (! OpenVpnManager.isVpnConnected()){ + return; + } + + if (OpenVpnManager.disconnect()) { + Toast t = Toast.makeText(this, getString(R.string.msg_vpn_disconnect), + Toast.LENGTH_LONG); + t.show(); + + } else { + Commons.showMessage(getString(R.string.msg_vpn_disconnect_error), this); + } + + } + + private void beginLauncVpn() throws Exception { + + if (OpenVpnManager.isVpnConnected()){ + // already connected; + return; + } + + if (!OpenVpnManager.isExternalAppInstalled(this)) { + Utils.logDebug("External VPN app not installed."); + return; + } + + if (getVpnNameIfAny() == null){ + Utils.logDebug("No vpn profile set. Exiting beginLaunchVpn()"); + return; + } + + // first, we make sure we have permission to use the vpn service. + Intent pi; + + try { + pi = OpenVpnManager.askApiPermissionsGetIntent(); + } catch (RemoteException e) { + Utils.logError("Exception while asking for VPN permission", e); + Toast t = Toast.makeText(getApplicationContext(), getString(R.string.msg_vpn_connect_error), Toast.LENGTH_LONG); + t.show(); + return; + + } + + if (pi == null){ + // no need to ask for permission + Utils.logDebug("No need for vpn permission: going to endLaunchVpn."); + endLaunchVpn(true); + + } else{ + // launch the intent to ask permission + Utils.logDebug("Need to ask for vpn permission. Starting intent.."); + startActivityForResult(pi, ActivityLauncher.RequestCode.VPN_PERMISSION); + } } + private void endLaunchVpn(boolean permissionGranted) { + + try { + + if (!permissionGranted) { + // warn user that permission must be granted + Utils.logDebug("User rejected vpn permission."); + String msg = getString(R.string.msg_vpn_no_permission).replace( + OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME); + Commons.showMessage(msg, this); + return; + } + + String profname = getVpnNameIfAny(); + + // check if profile exists + String profUuid = OpenVpnManager.getUuidFromName(profname); + if (profUuid == null){ + // warn user that selected profile doesn't exist + Commons.showMessage(getString(R.string.msg_vpn_wrong_profile), this); + return; + } + + if (OpenVpnManager.startVpn(profUuid)){ + Toast t = Toast.makeText(this, getString(R.string.msg_vpn_launched), Toast.LENGTH_LONG); + t.show(); + } else { + Commons.showMessage(getString(R.string.msg_vpn_connect_error),this); + } + + } catch (Exception e) { + Utils.logError("Exception while endLaunchVpn", e); + + } + + } + + private String getVpnNameIfAny(){ + + if (status == null) { + return null; + } + + AccessPointInfo i = status.getNetworkDetails(); + if (i == null) { + return null; + } + + String profname = i.getVpnProfileName(); + if (profname == null || profname.isEmpty()) { + return null; + } else { + return profname; + } + + } + public void onBtnMainClick(View v) { finish(); } @@ -126,5 +289,5 @@ public class ShowStatusActivity extends MenuEnabledActivity { public void onBackPressed() { moveTaskToBack(true); } - + } diff --git a/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java new file mode 100644 index 0000000..b9dab93 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java @@ -0,0 +1,201 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + +package fil.libre.repwifiapp.activities; + +import java.util.List; +import fil.libre.repwifiapp.ActivityLauncher; +import fil.libre.repwifiapp.Commons; +import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.ActivityLauncher.RequestCode; +import fil.libre.repwifiapp.helpers.AccessPointInfo; +import fil.libre.repwifiapp.helpers.OpenVpnManager; +import fil.libre.repwifiapp.helpers.Utils; +import android.os.Bundle; +import android.app.Activity; +import android.content.Intent; +import android.view.Menu; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Spinner; +import android.widget.TextView; + +public class VpnSettingsActivity extends Activity { + + private AccessPointInfo currentNetwork; + private Spinner spinProfile; + private TextView summaryView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_vpn_settings); + + String title = getString(R.string.title_activity_vpn_settings); + + Intent intent = getIntent(); + if (!intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) { + this.setResult(RESULT_CANCELED); + this.finish(); + return; + } + + this.currentNetwork = (AccessPointInfo) intent.getExtras().getSerializable( + ActivityLauncher.EXTRA_APINFO); + if (this.currentNetwork == null) { + this.setResult(RESULT_CANCELED); + this.finish(); + return; + } + + this.currentNetwork = Commons.storage.getSavedNetwork(currentNetwork); + this.spinProfile = (Spinner)findViewById(R.id.spin_vpn_profile); + this.summaryView = (TextView)findViewById(R.id.lbl_vpn_settings); + String summary = getString(R.string.summary_vpn_settings).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME); + summaryView.setText(summary); + + title += " " + currentNetwork.getSsid(); + this.setTitle(title); + + if (!checkExternalApp()){ + toggleSettingsEnabled(false); + } else { + initVpnManager(); + } + + } + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + + switch (requestCode) { + + case RequestCode.VPN_PERMISSION: + + if (resultCode != RESULT_OK) { + toggleSettingsEnabled(false); + Utils.logDebug("User rejected vpn permission."); + String msg = getString(R.string.msg_vpn_no_permission).replace( + OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME); + Commons.showMessage(msg, this); + return; + } + + break; + + default: + + break; + + } + + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + private void initVpnManager(){ + + try { + + Intent intentAllow = OpenVpnManager.askApiPermissionsGetIntent(); + if (intentAllow != null){ + startActivityForResult(intentAllow, ActivityLauncher.RequestCode.VPN_PERMISSION); + } + + List<String> profiles = OpenVpnManager.getExistingProfiles(); + if (profiles.size() == 0){ + String msg = getString(R.string.msg_vpn_no_profile).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME); + Commons.showMessage(msg, this); + toggleSettingsEnabled(false); + return; + } + Spinner spin = (Spinner)findViewById(R.id.spin_vpn_profile); + + ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item,profiles); + adapter.insert("",0); + spin.setAdapter(adapter); + spin.setSelection(adapter.getPosition(currentNetwork.getVpnProfileName())); + + } catch (Exception e) { + Utils.logError("Exception while creating openvpnmanager",e); + Commons.showMessage(getString(R.string.msg_vpn_connect_error)); + toggleSettingsEnabled(false); + } + + } + + private boolean checkExternalApp(){ + + if (! OpenVpnManager.isExternalAppInstalled(this)){ + String msg = getString(R.string.text_vpn_package_missing).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME); + Commons.showMessage(msg, this); + toggleSettingsEnabled(false); + return false; + } else { + return true; + } + + } + + private void toggleSettingsEnabled(boolean enabled){ + + spinProfile.setEnabled(enabled); + + Button b = (Button)findViewById(R.id.btn_save_vpn_settings); + b.setEnabled(enabled); + + } + + public void btnSaveClick(View v){ + + String vpnProf = (String)spinProfile.getSelectedItem(); + + /*if (! vpnProf.isEmpty()){ + // check if profile name exists + if( OpenVpnManager.getUuidFromName(vpnProf) == null){ + Commons.showMessage(getString(R.string.msg_vpn_wrong_profile), this); + return; + } + + }*/ + + // save profile + currentNetwork.setVpnProfileName(vpnProf); + Commons.storage.save(currentNetwork); + + terminate(); + + } + + public void btnBackClick(View v){ + terminate(); + } + + private void terminate(){ + finish(); + } + +} diff --git a/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java b/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java index d6e2eb3..eee569d 100644 --- a/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java +++ b/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java @@ -20,25 +20,38 @@ package fil.libre.repwifiapp.helpers; -import java.io.File; +import org.json.JSONException; +import org.json.JSONObject; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; -import fil.libre.repwifiapp.Commons; public class AccessPointInfo implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; private static final int MAX_SSID_LENGTH = 32; - + protected static final String SCAN_FILE_HDR = "bssid / frequency / signal level / flags / ssid"; + + private static final String JSONKEY_BSSID = "BSSID"; + private static final String JSONKEY_SSID = "SSID"; + private static final String JSONKEY_LASTUSED = "LastUsed"; + private static final String JSONKEY_AUTH = "Auth"; + private static final String JSONKEY_PSK = "PSK"; + private static final String JSONKEY_VPN_PROFILE = "VpnProfile"; + private static final String JSONKEY_DHCPSETS = "DhcpSettings"; + private String _ssid; private String _bssid; private String _auth; private String _level; private String _freq; private String _password; + private String _vpnProfileName = null; private boolean _isHidden = false; private long _lastTimeUsed; + private DhcpSettings _dhcpsets; public AccessPointInfo(String ssid, String bssid, String authType, String level, String freq) { @@ -50,6 +63,23 @@ public class AccessPointInfo implements Serializable { } + private AccessPointInfo(){ + // for inner use; + } + + public void setDhcpConfiguration(DhcpSettings sets) { + this._dhcpsets = sets; + } + + public DhcpSettings getDhcpConfiguration() { + + if (this._dhcpsets == null) { + return DhcpSettings.getDefault(); + } else { + return this._dhcpsets; + } + } + public String getSsid() { return this._ssid; } @@ -78,12 +108,42 @@ public class AccessPointInfo implements Serializable { this._bssid = bssid; } + public String getVpnProfileName(){ + if (_vpnProfileName == null){ + return ""; + } else { + return _vpnProfileName; + } + } + + public void setVpnProfileName(String profileName){ + _vpnProfileName = profileName; + } + public String getAuthType() { + if (_auth == null){ + return ""; + } return this._auth; } - public String getSignlalStrength() { - return this._level; + public int getSignlalStrength() { + // return this._level; + + if (this._level == null || this._level.isEmpty()) { + return 0; + } + + int retval = 0; + + try { + retval = Integer.parseInt(this._level); + } catch (NumberFormatException e) { + retval = 0; + } + + return retval; + } public String getFrequency() { @@ -116,6 +176,9 @@ public class AccessPointInfo implements Serializable { } public String getPassword() { + if (_password == null){ + return ""; + } return this._password; } @@ -170,19 +233,18 @@ public class AccessPointInfo implements Serializable { } - public static AccessPointInfo[] parseScanResult(String scanResultFile) { + public static AccessPointInfo[] parseScanResult(String scanResultContent) { try { - Utils.logDebug("AccesPointInfo trying to parse file: " + scanResultFile); - - File f = new File(scanResultFile); - if (!f.exists()) { - Utils.logError("AccessPointInfo.parseScanResult(): The provided scan result file doesn't exist"); + if (scanResultContent == null) { return null; } - String[] lines = Utils.readFileLines(scanResultFile); + Utils.logDebug("AccesPointInfo trying to parse file scan content:\n" + + scanResultContent); + + String[] lines = scanResultContent.split("\n"); List<AccessPointInfo> nets = new ArrayList<AccessPointInfo>(); if (lines == null) { @@ -190,7 +252,7 @@ public class AccessPointInfo implements Serializable { } for (String l : lines) { - if (l.startsWith(Commons.SCAN_FILE_HDR)) { + if (l.startsWith(SCAN_FILE_HDR)) { // strip off the header continue; } @@ -211,6 +273,8 @@ public class AccessPointInfo implements Serializable { } + sortInfosBySignalStrength(nets); + AccessPointInfo[] a = new AccessPointInfo[nets.size()]; a = nets.toArray(a); return a; @@ -222,4 +286,85 @@ public class AccessPointInfo implements Serializable { } + public JSONObject toJson(){ + + try { + + JSONObject j = new JSONObject(); + + j.put(JSONKEY_BSSID, getBssid()); + j.put(JSONKEY_SSID, getSsid()); + j.put(JSONKEY_PSK, getPassword()); + j.put(JSONKEY_AUTH, getAuthType()); + j.put(JSONKEY_LASTUSED, getLastTimeUsed()); + j.put(JSONKEY_VPN_PROFILE, getVpnProfileName()); + + DhcpSettings sets = getDhcpConfiguration(); + if (sets != null){ + JSONObject dhcpj = sets.toJson(); + if (dhcpj != null){ + j.put(JSONKEY_DHCPSETS, dhcpj); + } + + } + + return j; + + } catch (JSONException e) { + Utils.logError("Exception while converting AccessPointInfo to JSON.", e); + return null; + } + + } + + public static AccessPointInfo fromJsonObject(JSONObject json){ + + if (json == null || json.isNull(JSONKEY_BSSID) || json.isNull(JSONKEY_SSID)){ + return null; + } + + AccessPointInfo info = new AccessPointInfo(); + + try { + info._bssid = json.getString(JSONKEY_BSSID); + info._ssid = json.getString(JSONKEY_SSID); + info._auth = json.getString(JSONKEY_AUTH); + info._lastTimeUsed = json.getLong(JSONKEY_LASTUSED); + + if (json.has(JSONKEY_PSK) && ! json.isNull(JSONKEY_PSK)){ + info._password = json.getString(JSONKEY_PSK); + } + + if ( json.has(JSONKEY_VPN_PROFILE) && ! json.isNull(JSONKEY_VPN_PROFILE)){ + info._vpnProfileName = json.getString(JSONKEY_VPN_PROFILE); + } + + if (json.has(JSONKEY_DHCPSETS) && ! json.isNull(JSONKEY_DHCPSETS)){ + info._dhcpsets = DhcpSettings.fromJsonObject(json.getJSONObject(JSONKEY_DHCPSETS)); + } + + return info; + + } catch (JSONException e) { + Utils.logError("Exception while parsing json object to AccessPointInfo", e); + return null; + } + + + + + } + + private static void sortInfosBySignalStrength(List<AccessPointInfo> toSort) { + + Collections.sort(toSort, new Comparator<AccessPointInfo>() { + public int compare(AccessPointInfo o1, AccessPointInfo o2) { + if (o1.getSignlalStrength() == o2.getSignlalStrength()) + return 0; + return o1.getSignlalStrength() < o2.getSignlalStrength() ? -1 : 1; + } + }); + + } + } diff --git a/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java b/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java index c26dae9..e271dbe 100644 --- a/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java +++ b/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java @@ -20,6 +20,7 @@ package fil.libre.repwifiapp.helpers; +import fil.libre.repwifiapp.Commons; import java.io.Serializable; public class ConnectionStatus implements Serializable { @@ -37,7 +38,7 @@ public class ConnectionStatus implements Serializable { public String SSID; public String BSSID; public String IP; - + private static final String F_SEP = "="; private static final String KeyStatus = "wpa_state"; private static final String KeySSID = "ssid"; @@ -100,4 +101,9 @@ public class ConnectionStatus implements Serializable { } } + public AccessPointInfo getNetworkDetails(){ + AccessPointInfo i = new AccessPointInfo(SSID, BSSID, "","", ""); + return Commons.storage.getSavedNetwork(i); + } + } diff --git a/app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java b/app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java new file mode 100644 index 0000000..c0587a3 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java @@ -0,0 +1,205 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + +package fil.libre.repwifiapp.helpers; + +import org.apache.http.conn.util.InetAddressUtils; +import org.json.JSONException; +import org.json.JSONObject; +import java.io.Serializable; +import android.nfc.FormatException; + +public class DhcpSettings implements Serializable { + + private static final long serialVersionUID = 1L; + public boolean useDhcp; + private String _staticIP; + private int _mask; + private String _defGw; + + private static final String JSONKEY_DHCP = "DHCP"; + private static final String JSONKEY_STATIC_IP = "StaticIP"; + private static final String JSONKEY_GW = "Gateway"; + + public DhcpSettings(boolean useDhcp, String staticIP, String subnetMask, String defaultGateway) + throws FormatException { + this(useDhcp, staticIP, Utils.netmaskStringToInt(subnetMask), defaultGateway); + } + + public DhcpSettings(boolean useDhcp, String staticIP, int subnetMask, String defaultGatweay) + throws FormatException { + + this.useDhcp = useDhcp; + + if (!useDhcp) { + + if (!validateParams(staticIP, defaultGatweay, subnetMask)) { + throw new FormatException("Invalid dhcp parameters!"); + } + + this._staticIP = staticIP; + this._mask = subnetMask; + this._defGw = defaultGatweay; + + } + + } + + private DhcpSettings(){ + // inner use + } + + public static DhcpSettings parseSavedSettings(String staticIPwithMask, String defaultGateway){ + + try { + + String[] ipm = staticIPwithMask.split("/"); + String ip = ipm[0]; + int mask = Integer.parseInt(ipm[1]); + + return new DhcpSettings(false, ip, mask, defaultGateway); + + + } catch (Exception e) { + Utils.logError("Exception while parsing DhcpSettings for saved network. Reverting to dhcp.", e); + return null; + } + + } + + public static DhcpSettings getDefault(){ + try { + return new DhcpSettings(true, null, 24, null); + } catch (FormatException e) { + //no format exception can happen. + return null; + } + } + + private boolean validateParams(String ip, String gateway, int mask) { + + if (isValidAddress(ip) && isValidAddress(gateway) && isValidMask(mask)) { + return true; + } else { + return false; + } + + } + + public static boolean isValidAddress(String ipAddress){ + return InetAddressUtils.isIPv4Address(ipAddress); + } + + public static boolean isValidMaks(String mask){ + int m = Utils.netmaskStringToInt(mask); + return isValidMask(m); + } + + public static boolean isValidMask(int mask){ + if (mask >= 8 && mask <= 32){ + return true; + }else{ + return false; + } + } + + public String getStaticIP() { + if (_staticIP == null){ + return ""; + } + return _staticIP; + } + + public String getStaticIPwithMask() { + return getStaticIP() + "/" + String.valueOf(getSubnetMaskInt()); + } + + public int getSubnetMaskInt() { + return _mask; + } + + public String getSubnetMaskString(){ + String v = Utils.netmaskIntToString(_mask); + if (v == null){ + return ""; + } + return v; + } + + public String getDefaultGateway() { + if (_defGw == null){ + return ""; + } + return _defGw; + } + + public JSONObject toJson(){ + + JSONObject j = new JSONObject(); + + try { + j.put(JSONKEY_DHCP, useDhcp); + j.put(JSONKEY_GW, getDefaultGateway()); + j.put(JSONKEY_STATIC_IP, getStaticIPwithMask()); + + return j; + + } catch (JSONException e) { + Utils.logError("Exception while converting DhcpSettings to JSON.", e); + return null; + } + + + } + + public static DhcpSettings fromJsonObject(JSONObject json){ + + if (json == null){ + return null; + } + + DhcpSettings sets = new DhcpSettings(); + + try { + + sets.useDhcp = json.getBoolean(JSONKEY_DHCP); + + if (json.has(JSONKEY_GW) && ! json.isNull(JSONKEY_GW)){ + sets._defGw = json.getString(JSONKEY_GW); + } + + if (json.has(JSONKEY_STATIC_IP) && !json.isNull(JSONKEY_STATIC_IP)){ + + String[] splt = json.getString(JSONKEY_STATIC_IP).split("/"); + sets._staticIP = splt[0]; + sets._mask = Integer.parseInt(splt[1]); + + } + + return sets; + + } catch (Exception e) { + Utils.logError("Exception while parsing json object to DhcpSettings", e); + return null; + } + + } + +} diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine.java b/app/src/fil/libre/repwifiapp/helpers/Engine.java index 68d8745..225d993 100644 --- a/app/src/fil/libre/repwifiapp/helpers/Engine.java +++ b/app/src/fil/libre/repwifiapp/helpers/Engine.java @@ -22,167 +22,33 @@ package fil.libre.repwifiapp.helpers; import java.net.NetworkInterface; import java.net.SocketException; -import java.util.ArrayList; import java.util.Enumeration; -import fil.libre.repwifiapp.Commons; public abstract class Engine implements IEngine { - - protected String getCmdWpaSup() { - return "wpa_supplicant -B -dd -i" + Commons.INTERFACE_NAME + " -C" + Commons.SOCKET_DIR - + " -P" + Commons.PID_FILE + " -I" + Commons.OVERLAY_FILE + " -e" - + Commons.ENTROPY_FILE; - } - - protected String getCmdWpaCli() { - return "wpa_cli -p" + Commons.SOCKET_DIR + " -P" + Commons.PID_FILE + " -i" - + Commons.INTERFACE_NAME; - } - - protected abstract String getCmdWpaStart(); - - public boolean deleteFileIfExists(String filePath) { - - if (filePath == null) { - return false; - } - - if (filePath.contains("*")) { - // it's safer to reject bulk rm'ing - return false; - } - - if (filePath.contains(" -r ")) { - // only file rm'ing acceppted - return false; - } - - // needs root (it only gets used by the 4p2 engine, working in - // /data/misc/wifi) - return executeRootCmd("if [ -e \"" + filePath + "\" ]; then rm \"" + filePath + "\"; fi"); - - } - - public boolean chmodFile(String filePath, String mod) { - // needs root (chmod) - return executeRootCmd("chmod " + mod + " \"" + filePath + "\""); - } - - @Override - public boolean killBackEndProcesses() { - - // needs root (for killall) - - Utils.logDebug("killing wpa_supplicant..:"); - if (executeRootCmd("killall -SIGINT wpa_supplicant")) { - Utils.logDebug("Killed wpa_supplicant"); - } else { - Utils.logDebug("Wpa_supplicant NOT killed."); - } - - Utils.logDebug("killing dhcpcd.."); - if (executeRootCmd("killall -SIGINT dhcpcd")) { - Utils.logDebug("Killed dhcpcd"); - } else { - Utils.logDebug("dhcpcd NOT killed."); - } - - return true; - - } - - @Override - public boolean clearWorkingDir() { - - // needs root (to work within /data/misc/wifi) - - Utils.logDebug("clearWorkingDir():"); - - if (executeRootCmd("rm -r " + Commons.SOCKET_DIR)) { - Utils.logDebug("removed socket dir"); - } - - if (executeRootCmd("rm " + Commons.ENTROPY_FILE)) { - Utils.logDebug("removed entropy file"); - } - - if (executeRootCmd("rm " + Commons.PID_FILE)) { - Utils.logDebug("removed pidfile"); - } - - if (executeRootCmd("rm " + Commons.SOFTAP_FILE)) { - Utils.logDebug("removed softap file"); - } - - if (executeRootCmd("rm " + Commons.WPA_CONF)) { - Utils.logDebug("removed wpa conf file"); - } - - if (executeRootCmd("rm " + Commons.P2P_CONF)) { - Utils.logDebug("removed p2p conf file"); - } - - return true; - - } - - @Override - public boolean startWpaSupplicant() { - - Utils.logDebug("startWpaSupplicant():"); - - // needs root (for wpa_supplicant) - if (executeRootCmd(getCmdWpaSup())) { - return true; - } else { - Utils.logDebug("Failed to start wpa"); - return false; - } - - } - + @Override public AccessPointInfo[] getAvailableNetworks() { Utils.logDebug("getAvailableNetworks():"); - // killPreviousConnections(); - - // Is it really necessary??? - // seems that clearing /data/misc/wifi is NOT necessary - // so, commented out - Fil 2017-03-24 - /* - * if (! clearWorkingDir()){ Utils.logError("Failed clearing dir"); - * return null; } - */ - - if (!startWpaSupplicant()) { + if (!WpaSupplicant.start()) { Utils.logError("Failed starting wpa_supplicant"); return null; } - if (!createScanScripts()) { - Utils.logError("Failed creating scripts"); - return null; - } - - if (!scanNetworks()) { + if (!WpaCli.scanNetworks()) { Utils.logError("failed scanning networks"); return null; } - if (!getScanResults()) { + String scanRes = WpaCli.getScanResults(); + + if (scanRes == null) { Utils.logError("failed getting scan results"); return null; } - // chmod 664 scan_file to make it readable - /* - * if (!chmodFile(Commons.getScanFile(), "664")){ - * Utils.logError("failed chmodding scan_file"); return null; } - */ - - AccessPointInfo[] a = AccessPointInfo.parseScanResult(Commons.getScanFile()); + AccessPointInfo[] a = AccessPointInfo.parseScanResult(scanRes); if (a == null) { Utils.logError("Unable to parse scan file into AccessPointInfo array"); return a; @@ -200,30 +66,8 @@ public abstract class Engine implements IEngine { @Override public boolean disconnect() { - // needs root (for wpa_cli) - - if (!isWpaSupplicantRunning()) { - return true; - } - - try { + return WpaCli.disconnect(); - RootCommand su = new RootCommand(getCmdWpaCli() + " disconnect"); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while enabling network", e); - return false; - } } /*** @@ -231,51 +75,12 @@ public abstract class Engine implements IEngine { */ @Override public ConnectionStatus getConnectionStatus() { - - Utils.logDebug("called getConnecitonStatus()"); - if (!isWpaSupplicantRunning()) { - // wpa_supplicant is not running. - // unable to determin status. - Utils.logDebug("wpa not running, cannot get connection status."); - return null; - - } - - try { - - RootCommand su = new RootCommand(getCmdWpaCli() + " status"); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out == null || out.trim().equals("")) { - return null; - } else { - return ConnectionStatus.parseWpaCliOutput(out); - } - } else { - return null; - } - - } catch (Exception e) { - Utils.logError("Error while executing wpa_cli status", e); - return null; - } - + return WpaCli.getConnectionStatus(); } @Override public boolean isInterfaceAvailable(String ifaceName) throws SocketException { - /* - * String[]ifaces = getAvailableInterfaces(); if(ifaces == null || - * ifaces.length == 0){ return false; } - * - * for(String name : ifaces){ - * - * if (name.equals(ifaceName)){ return true; } } - * - * return false; - */ - Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface nif = interfaces.nextElement(); @@ -288,182 +93,40 @@ public abstract class Engine implements IEngine { } - @Override - public String[] getAvailableInterfaces() { - - try { - - // No need for root for "ip link" - // tested 2017-03-24 - Fil - ShellCommand cmd = new ShellCommand("ip link"); - if (cmd.execute() == 0) { - - String out = cmd.getOutput(); - if (out == null || out.contains("\n") == false) { - Utils.logDebug("No out from ip link"); - return null; - } - - ArrayList<String> list = new ArrayList<String>(); - - String[] lines = out.split("\n"); - for (String l : lines) { - - String[] fields = l.split(":"); - if (fields.length != 3) { - continue; - } - - String interfName = fields[1].trim(); - list.add(interfName); - - } - - String[] retArr = new String[list.size()]; - retArr = list.toArray(retArr); - - return retArr; - - } else { - return null; - } - - } catch (Exception e) { - Utils.logError("Error while querying ip link", e); - return null; - } - - } - public boolean runDhcpcd() { - // needs root - return executeRootCmd("dhcpcd " + Commons.INTERFACE_NAME); - - } - + // option -w avoids dhcpcd forking to background, + // in order to keep control over its exit code, and be able to wait for it. + // option -A avoids ARP IP checking, we use it to save some seconds in the connection process. + return RootCommand.executeRootCmd("dhcpcd -w -A " + WpaSupplicant.INTERFACE_NAME); + + } + + public boolean runDhcpcd(DhcpSettings dhcpConfig) { + + if (dhcpConfig == null || dhcpConfig.useDhcp){ + Utils.logDebug("running dhchpc without dhcp settings, reverting to dhcp"); + return runDhcpcd(); + } + + Utils.logDebug("Running dhcpcd with custom ip settings"); + String cmdMask = "dhcpcd -w -A -S ip_address=%s -S routers=%s %s"; + String cmd = String.format(cmdMask, + dhcpConfig.getStaticIPwithMask(), + dhcpConfig.getDefaultGateway(), + WpaSupplicant.INTERFACE_NAME); + + return RootCommand.executeRootCmd(cmd); + + } + + public static boolean killDhcpcd(){ + return RootCommand.executeRootCmd("killall -SIGINT dhcpcd"); + } + public boolean interfaceUp() { // needs root (tested) - return executeRootCmd("ifconfig " + Commons.INTERFACE_NAME + " up"); - } - - /* - * protected boolean executeCmd(String cmd){ - * - * try { - * - * ShellCommand c = new ShellCommand(cmd); if ( c.execute() == 0){ return - * true; }else { return false; } - * - * } catch (Exception e) { Utils.logError("Error executing \"" + cmd + - * "\"",e); return false; } - * - * } - */ - - protected boolean executeRootCmd(String cmd) { - - try { - - RootCommand c = new RootCommand(cmd); - if (c.execute() == 0) { - return true; - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error executing \"" + cmd + "\"", e); - return false; - } - } - - protected boolean isWpaSupplicantRunning() { - - boolean retval = false; - - try { - - RootCommand su = new RootCommand("pidof wpa_supplicant"); - if (su.execute() == 0) { - - if (su.getOutput().trim().equals("")) { - retval = false; - } else { - retval = true; - } - - } else { - retval = false; - } - - } catch (Exception e) { - Utils.logError("Exception during isWpaSupplicantRunning()", e); - retval = false; - } - - return retval; - - } - - protected boolean scanNetworks() { - - // needs root (for wpa_supplicant and wpa_cli) - return executeRootCmd("bash " + Commons.getScriptScan()); - - } - - protected boolean getScanResults() { - - // needs root (for wpa_supplicant and wpa_cli) - boolean res = executeRootCmd("bash " + Commons.getScriptScanRes()); - if (!res) { - return false; - } - return res; - - } - - protected boolean createScanScripts() { - - try { - - String scan = getCmdWpaCli() + " scan\n" + "if [ $? -ne 0 ]; then\n" + "exit 1\n" - + "fi\n" + "sleep 2s\n"; - - String scanRes = "if [ -e \"" + Commons.getScanFile() + "\" ]; then\n" + " rm \"" - + Commons.getScanFile() + "\"\n" + "fi\n" + getCmdWpaCli() - + " scan_results > \"" + Commons.getScanFile() + "\"\n" - + "if [ $? -ne 0 ]; then\n" + " exit 1\n" + "fi\n"; - - if (!Utils.writeFile(Commons.getScriptScan(), scan, true)) { - - Exception e = Utils.getLastException(); - if (e != null) { - Utils.logError("Error while writing scan script.", e); - } - - return false; - } - - if (!Utils.writeFile(Commons.getScriptScanRes(), scanRes, true)) { - - Exception e = Utils.getLastException(); - if (e != null) { - Utils.logError("Error while writing getScanResults script.", e); - } - - return false; - } - - return true; - - } catch (Exception e) { - - Utils.logError("Error while creating the scanning script.", e); - return false; - } - + return RootCommand.executeRootCmd("ifconfig " + WpaSupplicant.INTERFACE_NAME + " up"); } } diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java b/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java index d4ff0f7..3eff6c8 100644 --- a/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java +++ b/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java @@ -26,16 +26,9 @@ import fil.libre.repwifiapp.Commons; public class Engine6p0 extends Engine { @Override - protected String getCmdWpaStart() { - return "wpa_supplicant -B -dd -i" + Commons.INTERFACE_NAME + " -C" + Commons.SOCKET_DIR - + " -P" + Commons.PID_FILE + " -I" + Commons.OVERLAY_FILE + " -e" - + Commons.ENTROPY_FILE; - } - - @Override public boolean connect(AccessPointInfo info) { - killBackEndProcesses(); + WpaSupplicant.kill(); if (info == null) { Utils.logDebug("Engine's connect() received a null AccessPointInfo"); @@ -62,81 +55,81 @@ public class Engine6p0 extends Engine { // launch wpa_supplicant specifying our custom configuration and the // socket file - if (!executeRootCmd(getCmdWpaStart())) { + if (!WpaSupplicant.start()) { Utils.logDebug("Unable to run wpa start"); return false; } // create new network and get network id - String netID = createNetworkGetId(); + String netID = WpaCli.createNetworkGetId(); if (netID == null) { Utils.logDebug("Unable to fetch network id"); return false; } // set network SSID - if (!setNetworkSSID(info.getSsid(), netID)) { + if (!WpaCli.setNetworkSSID(info.getSsid(), netID)) { Utils.logDebug("Failed to set network ssid"); return false; } - if (info.isHidden() && !setNetworkScanSSID(netID)) { + if (info.isHidden() && !WpaCli.setNetworkScanSSID(netID)) { Utils.logDebug("Failed to set scan_ssid 1 for hidden network."); return false; } // set password (if any) - if (!setNetworkPSK(info, netID)) { + if (!WpaCli.setNetworkPSK(info, netID)) { Utils.logDebug("Failed to set network psk"); return false; } // select the network we just created - if (!selectNetwork(netID)) { + if (!WpaCli.selectNetwork(netID)) { Utils.logDebug("Unable to wpa_cli select network"); return false; } // enable the newtork - if (!enableNetwork(netID)) { + if (!WpaCli.enableNetwork(netID)) { Utils.logDebug("Unable to wpa_cli enable_newtork"); return false; } - - // try to reassociate to Access Point - /* - * if (! reassociate()){ - * Utils.logDebug("Unable to wpa_cli reassociate"); return false; } - */ + + // kill previous dhchcd instances + if (!RootCommand.executeRootCmd("killall -SIGINT dhcpcd")){ + Utils.logError("Unable to kill previous instances of dhcpcd"); + } // get DHCP Utils.logDebug("Attempt to run dhcpcd.."); - if (!runDhcpcd()) { + if (!runDhcpcd(info.getDhcpConfiguration())) { Utils.logDebug("Failed to run dhcpcd"); return false; } // try to fetch gateway - String gw = getGateway(); - if (gw == null || gw.trim().length() < 7) { + String gw = getGateWayTimeout(Commons.WAIT_FOR_GATEWAY); + if (gw == null || !InetAddressUtils.isIPv4Address(gw)) { // failed to get gateway Utils.logDebug("Failed to get gateway"); return false; } - if (!executeRootCmd("ndc network create 1")) { + if (!RootCommand.executeRootCmd("ndc network create 1")) { Utils.logDebug("Failed to wpa_cli network create 1 "); return false; } - if (!executeRootCmd("ndc network interface add 1 " + Commons.INTERFACE_NAME)) { + if (!RootCommand.executeRootCmd("ndc network interface add 1 " + + WpaSupplicant.INTERFACE_NAME)) { Utils.logDebug("Failed to add interface."); return false; } // set route to gateway for all traffic - if (!executeRootCmd("ndc network route add 1 " + Commons.INTERFACE_NAME + " 0.0.0.0/0 " - + gw)) { + if (!RootCommand.executeRootCmd("ndc network route add 1 " + WpaSupplicant.INTERFACE_NAME + + " 0.0.0.0/0 " + gw)) { Utils.logDebug("Failed to add route to gateway"); return false; } @@ -147,7 +140,7 @@ public class Engine6p0 extends Engine { } // use network - if (!executeRootCmd("ndc network default set 1")) { + if (!RootCommand.executeRootCmd("ndc network default set 1")) { Utils.logDebug("Failed to set network as default"); return false; } @@ -156,163 +149,9 @@ public class Engine6p0 extends Engine { } - private String createNetworkGetId() { - - try { - - RootCommand su = new RootCommand(getCmdWpaCli() + " add_network"); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out == null || out.trim().equals("")) { - return null; - } else { - return out.replace("\n", ""); - } - } else { - return null; - } - - } catch (Exception e) { - Utils.logError("Error while creating network", e); - return null; - } - - } - private boolean destroyNetwork() { // needs root (tested) - return executeRootCmd("ndc network destroy 1"); - } - - private boolean setNetworkSSID(String ssid, String networkID) { - - try { - - // needs root (wpa_cli) - RootCommand su = new RootCommand(getCmdWpaCli() + " set_network " + networkID - + " ssid '\"" + ssid + "\"'"); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while setting network SSID", e); - return false; - } - - } - - private boolean setNetworkPSK(AccessPointInfo info, String networkID) { - - try { - - // needs root (wpa_cli) - - String cmdSetPass = null; - if (info.needsPassword()) { - cmdSetPass = getCmdWpaCli() + " set_network " + networkID + " psk '\"" - + info.getPassword() + "\"'"; - } else { - cmdSetPass = getCmdWpaCli() + " set_network " + networkID + " key_mgmt NONE"; - } - - RootCommand su = new RootCommand(cmdSetPass); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while setting network PSK", e); - return false; - } - - } - - private boolean setNetworkScanSSID(String networkID) { - - try { - - // needs root (wpa_cli) - RootCommand su = new RootCommand(getCmdWpaCli() + " set_network " + networkID - + " scan_ssid 1"); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while setting network SSID", e); - return false; - } - } - - private boolean selectNetwork(String networkID) { - - try { - - // needs root (wpa_cli) - RootCommand su = new RootCommand(getCmdWpaCli() + " select_network " + networkID); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while selecting network", e); - return false; - } - - } - - private boolean enableNetwork(String networkID) { - - try { - - // needs root (wpa_cli) - - RootCommand su = new RootCommand(getCmdWpaCli() + " enable_network " + networkID); - if (su.execute() == 0) { - String out = su.getOutput(); - if (out != null && out.trim().replace("\n", "").equals("OK")) { - return true; - } else { - return false; - } - } else { - return false; - } - - } catch (Exception e) { - Utils.logError("Error while enabling network", e); - return false; - } - + return RootCommand.executeRootCmd("ndc network destroy 1"); } private boolean setDns(String[] dnss, String gateway) { @@ -343,7 +182,42 @@ public class Engine6p0 extends Engine { cmd += " " + dnss[0]; } - return executeRootCmd(cmd); + return RootCommand.executeRootCmd(cmd); + } + + private String getGateWayTimeout(int timeoutMillis) { + + String gw = getGateway(); + if (gw != null && !gw.trim().isEmpty()) { + return gw; + } + + Utils.logDebug("Gateway not available.. going into wait loop.."); + + // gateway not (yet) available + // waits for a maximum of timeoutMillis milliseconds + // to let the interface being registered. + int msWaited = 0; + while (msWaited < timeoutMillis) { + + try { + Thread.sleep(100); + } catch (Exception e) { + return null; + } + msWaited += 100; + + gw = getGateway(); + if (gw != null && !gw.trim().isEmpty()) { + Utils.logDebug("Gateway found after wait loop!"); + return gw; + } + } + + // unable to get gateway + Utils.logError("Gateway not found after wait loop."); + return null; + } private String getGateway() { @@ -351,7 +225,7 @@ public class Engine6p0 extends Engine { try { // doesn't need root (tested) - RootCommand cmd = new RootCommand("ip route show dev " + Commons.INTERFACE_NAME); + ShellCommand cmd = new ShellCommand("ip route show dev " + WpaSupplicant.INTERFACE_NAME); if (cmd.execute() != 0) { Utils.logDebug("command failed show route"); return null; @@ -390,7 +264,8 @@ public class Engine6p0 extends Engine { private boolean clearAddrs() { // needs root (tested) - return executeRootCmd("ndc interface clearaddrs " + Commons.INTERFACE_NAME); + return RootCommand.executeRootCmd("ndc interface clearaddrs " + + WpaSupplicant.INTERFACE_NAME); } }
\ No newline at end of file diff --git a/app/src/fil/libre/repwifiapp/helpers/IEngine.java b/app/src/fil/libre/repwifiapp/helpers/IEngine.java index 037cf62..26ebddb 100644 --- a/app/src/fil/libre/repwifiapp/helpers/IEngine.java +++ b/app/src/fil/libre/repwifiapp/helpers/IEngine.java @@ -24,12 +24,6 @@ import java.net.SocketException; public interface IEngine { - public boolean startWpaSupplicant(); - - public boolean killBackEndProcesses(); - - public boolean clearWorkingDir(); - public AccessPointInfo[] getAvailableNetworks(); public boolean connect(AccessPointInfo info); @@ -40,6 +34,4 @@ public interface IEngine { public boolean isInterfaceAvailable(String ifaceName) throws SocketException; - public String[] getAvailableInterfaces(); - } diff --git a/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java b/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java index db27f7e..96805a6 100644 --- a/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java +++ b/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java @@ -20,13 +20,16 @@ package fil.libre.repwifiapp.helpers; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.File; import java.util.ArrayList; public class NetworkManager { + private static final String VERSION_NOTE = "RepWifiStorageVersion: 2.0\n"; private static final String F_SEP = "\t"; - private static final int NET_MAX_AGE = 365; // Expressed in days + private static final int NET_MAX_AGE = 1095; // Expressed in days private String _knownNetworksFile = null; @@ -34,7 +37,7 @@ public class NetworkManager { this._knownNetworksFile = networksFilePath; } - private AccessPointInfo searchInFile(AccessPointInfo i) { + private AccessPointInfo getSavedInfo(AccessPointInfo i) { if (i == null) { return null; @@ -63,12 +66,16 @@ public class NetworkManager { // then return the best match (only ssid), if any if (toTest.getSsid().equals(ssid)) { + i.setPassword(toTest.getPassword()); + i.setDhcpConfiguration(toTest.getDhcpConfiguration()); + i.setVpnProfileName(toTest.getVpnProfileName()); + if (toTest.getBssid().equals(bssid)) { - i.setPassword(toTest.getPassword()); + // complete match, return. return i; } else { - i.setPassword(toTest.getPassword()); + // probable match ret = i; } @@ -82,11 +89,6 @@ public class NetworkManager { private boolean saveOrRemove(AccessPointInfo info, boolean save) { - String iText = InfoToString(info); - if (iText == null) { - return false; - } - AccessPointInfo[] existingNets = getKnownNetworks(); ArrayList<AccessPointInfo> newlist = new ArrayList<AccessPointInfo>(); @@ -151,7 +153,7 @@ public class NetworkManager { } - private AccessPointInfo getFromString(String savedString) { + private AccessPointInfo getFromStringOld(String savedString) { if (savedString == null || savedString.trim().equals("")) { return null; @@ -168,11 +170,25 @@ public class NetworkManager { String pass = fields[2]; String lastUsed = fields[3]; String auth = null; + String ipWmask = null; + String gw = null; + boolean useDhcp = true; + String vpnProfile = null; if (fields.length > 4) { auth = fields[4]; } + if (fields.length > 6) { + ipWmask = fields[5]; + gw = fields[6]; + useDhcp = false; + } + + if (fields.length > 7) { + vpnProfile = fields[7]; + } + long lastusedmillis = 0; try { lastusedmillis = Long.parseLong(lastUsed); @@ -189,69 +205,129 @@ public class NetworkManager { AccessPointInfo i = new AccessPointInfo(ssid, bssid, auth, null, null); i.setPassword(pass); i.setLastTimeUsed(lastusedmillis); + i.setVpnProfileName(vpnProfile); + + if (!useDhcp) { + DhcpSettings s = DhcpSettings.parseSavedSettings(ipWmask, gw); + i.setDhcpConfiguration(s); + } return i; } - private String InfoToString(AccessPointInfo info) { + private boolean saveList(AccessPointInfo[] list) { - if (info == null) { - return null; - } + try { - String bssid = info.getBssid(); - String ssid = info.getSsid(); - String pass = info.getPassword(); - String tsLastUsed = "" + info.getLastTimeUsed(); - String auth = info.getAuthType(); + JSONArray jarr = new JSONArray(); + for (AccessPointInfo i : list) { - if (bssid == null || bssid.trim().equals("")) { - return null; - } + JSONObject jo = i.toJson(); + if (jo == null) { + return false; + } - if (ssid == null || ssid.trim().equals("")) { - return null; - } + jarr.put(jo); - if (pass == null || pass.trim().equals("")) { - return null; - } + } + + StringBuilder sb = new StringBuilder(); + sb.append(VERSION_NOTE); + sb.append("\n"); + + sb.append(jarr.toString(2)); + + return Utils.writeFile(_knownNetworksFile, sb.toString(), true); - if (auth == null) { - auth = ""; + } catch (Exception e) { + Utils.logError("Exception while saving AccessPointInfo array to JSON-formatted file.", + e); + return false; } - String iText = info.getBssid() + F_SEP + info.getSsid() + F_SEP + info.getPassword() - + F_SEP + tsLastUsed + F_SEP + auth; - return iText; + /* + * if (list == null) { return false; } + * + * String[] lines = new String[list.length]; + * + * for (int i = 0; i < list.length; i++) { + * + * String storeString = InfoToString(list[i]); if (storeString == null) + * { return false; } lines[i] = storeString; + * + * } + * + * return Utils.writeFileLines(this._knownNetworksFile, lines, true); + */ } - private boolean saveList(AccessPointInfo[] list) { + public boolean updateStorageVersion() { - if (list == null) { - return false; + String[] lines = Utils.readFileLines(_knownNetworksFile); + if (lines.length == 0) { + return true; } - String[] lines = new String[list.length]; + if (lines[0].trim().equals(VERSION_NOTE)) { + return true; - for (int i = 0; i < list.length; i++) { + } else { - String storeString = InfoToString(list[i]); - if (storeString == null) { - return false; + AccessPointInfo[] infos = getKnownNetworksOld(); + if (infos == null || infos.length == 0) { + return true; } - lines[i] = storeString; + return saveList(infos); } - return Utils.writeFileLines(this._knownNetworksFile, lines, true); - } public AccessPointInfo[] getKnownNetworks() { + try { + + String fconts = Utils.readFile(_knownNetworksFile); + if (fconts == null) { + return null; + } + + if (!fconts.startsWith(VERSION_NOTE)) { + // wrong version, try to convert it + if (updateStorageVersion()) { + return getKnownNetworks(); + } else { + return null; + } + } + + JSONArray jarr = new JSONArray(fconts.replace(VERSION_NOTE, "")); + ArrayList<AccessPointInfo> list = new ArrayList<AccessPointInfo>(); + + int count = 0; + for (int i = 0; i < jarr.length(); i++) { + AccessPointInfo info = AccessPointInfo.fromJsonObject(jarr.getJSONObject(i)); + if (info == null) { + continue; + } + count += 1; + list.add(info); + } + + AccessPointInfo[] arr = new AccessPointInfo[count]; + return list.toArray(arr); + + } catch (Exception e) { + Utils.logError("Exception while parsing JSON content from storage file.", e); + return null; + } + + } + + public AccessPointInfo[] getKnownNetworksOld() { + ArrayList<AccessPointInfo> list = new ArrayList<AccessPointInfo>(); File f = new File(this._knownNetworksFile); @@ -266,7 +342,7 @@ public class NetworkManager { for (String l : lines) { - AccessPointInfo info = getFromString(l); + AccessPointInfo info = getFromStringOld(l); if (info != null) { list.add(info); } @@ -282,7 +358,7 @@ public class NetworkManager { public boolean isKnown(AccessPointInfo info) { - AccessPointInfo i = searchInFile(info); + AccessPointInfo i = getSavedInfo(info); if (i == null) { return false; } else { @@ -300,7 +376,7 @@ public class NetworkManager { } public AccessPointInfo getSavedNetwork(AccessPointInfo i) { - return searchInFile(i); + return getSavedInfo(i); } } diff --git a/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java b/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java new file mode 100644 index 0000000..5de2501 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java @@ -0,0 +1,237 @@ +// +// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// +// This file is part of RepWifiApp. +// This file is based upon the example file included in +// de.blinkt.openvpn package by Arne Schwabe. +// +// RepWifiApp is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RepWifiApp is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>. +// +// ******************************************************************** + +package fil.libre.repwifiapp.helpers; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.IBinder; +import android.os.RemoteException; +import java.util.ArrayList; +import java.util.List; +import de.blinkt.openvpn.api.APIVpnProfile; +import de.blinkt.openvpn.api.IOpenVPNAPIService; + +public class OpenVpnManager { + + public static final String SERVICE_PACKAGE_NAME = "de.blinkt.openvpn"; + public static final String APP_COMMON_NAME = "OpenVPN for Android"; + public static final String PLACEHOLDER_APPNAME = "[VPN_EXT_APP]"; + + private static boolean VpnIsConnected; + private static OpenVpnManager _currentInstance; + + protected IOpenVPNAPIService _vpnSvc; + + private Activity _caller; + private ServiceConnection _svcConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + _vpnSvc = IOpenVPNAPIService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName className) { + _vpnSvc = null; + } + }; + + private OpenVpnManager(Activity c) throws Exception { + this._caller = c; + bindService(); + } + + private void bindService() throws Exception { + + Intent intentGetService = new Intent(IOpenVPNAPIService.class.getName()); + intentGetService.setPackage(SERVICE_PACKAGE_NAME); + if (!_caller.bindService(intentGetService, _svcConnection, Context.BIND_AUTO_CREATE)) { + throw new Exception("FAILED to bind to OpenVPN service!"); + } + + } + + private void unbindService() { + _caller.unbindService(_svcConnection); + } + + private Intent askApiPermissionsGetIntentInternal() throws RemoteException { + return _vpnSvc.prepare(_caller.getPackageName()); + } + + private boolean startVpnInternal(String profileUuid) { + + if (profileUuid == null) { + Utils.logError("Invoked startVpn with null uuid"); + return false; + } + + if (_vpnSvc == null) { + Utils.logError("Invoked startVpn but inner service is null."); + return false; + } + + try { + + _vpnSvc.startProfile(profileUuid); + VpnIsConnected = true; + return true; + + } catch (RemoteException e) { + Utils.logError("Exception while starting vpn.", e); + return false; + } + } + + private boolean disconnectInternal() { + + if (_vpnSvc == null) { + Utils.logDebug("Attempted to disconnect from VPN, but inner service is null"); + VpnIsConnected = false; + return true; + } + + try { + _vpnSvc.disconnect(); + VpnIsConnected = false; + return true; + } catch (RemoteException e) { + Utils.logError("Exception while disconnecting from vpn.", e); + return false; + } + } + + private List<String> getExistingProfilesInternal(){ + + try { + List<APIVpnProfile> list = _vpnSvc.getProfiles(); + + List<String> ret = new ArrayList<String>(); + for (APIVpnProfile vp : list) { + ret.add(vp.mName); + } + + return ret; + + } catch (RemoteException e) { + Utils.logError("Exception while retrieving profiles from vpn service.", e); + return null; + } + + } + + private String getUuidFromNameInternal(String profileName) { + + if (_vpnSvc == null) { + Utils.logError("Called getUuidFromName but inner service is null!"); + return null; + } + + try { + List<APIVpnProfile> list = _vpnSvc.getProfiles(); + + for (APIVpnProfile vp : list) { + if (vp.mName.equals(profileName)) { + return vp.mUUID; + } + } + + return null; + + } catch (RemoteException e) { + Utils.logError("Exception while retrieving profiles from vpn service.", e); + return null; + } + } + + public void close() { + if (_vpnSvc != null) { + unbindService(); + + } + + } + + public static void initialize(Activity caller){ + + if (_currentInstance != null){ + return; + } + + try { + _currentInstance = new OpenVpnManager(caller); + } catch (Exception e) { + Utils.logError("Exception while initializing vpn manager.",e); + } + } + + public static boolean isExternalAppInstalled(Activity caller) { + + try { + + ApplicationInfo i; + i = caller.getPackageManager().getApplicationInfo(SERVICE_PACKAGE_NAME, 0); + return (i != null); + + } catch (NameNotFoundException e) { + return false; + } + + } + + public static boolean startVpn(String profileUuid){ + if (_currentInstance == null){ + return false; + } + return _currentInstance.startVpnInternal(profileUuid); + } + + public static boolean disconnect(){ + if (_currentInstance == null){ + return false; + } + return _currentInstance.disconnectInternal(); + } + + public static boolean isVpnConnected(){ + return VpnIsConnected; + } + + public static String getUuidFromName(String profileName){ + if (_currentInstance == null){ + return null; + } + return _currentInstance.getUuidFromNameInternal(profileName); + } + + public static List<String> getExistingProfiles(){ + return _currentInstance.getExistingProfilesInternal(); + } + + public static Intent askApiPermissionsGetIntent() throws RemoteException{ + return _currentInstance.askApiPermissionsGetIntentInternal(); + } + +} diff --git a/app/src/fil/libre/repwifiapp/helpers/RootCommand.java b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java index 9d9f7d3..bd859c8 100644 --- a/app/src/fil/libre/repwifiapp/helpers/RootCommand.java +++ b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java @@ -22,71 +22,89 @@ package fil.libre.repwifiapp.helpers; import java.io.DataOutputStream; import java.io.InputStream; -import fil.libre.repwifiapp.Commons; + public class RootCommand extends ShellCommand { + // protected static final String CMD_WRAPPING = "export TEMPOUT=\"$(%s)\";echo \"$TEMPOUT\";exit $?"; + protected static final String CMD_WRAPPING = "TEMPOUT=\"$(%s)\";ec=$?;echo \"$TEMPOUT\";exit $ec"; + public RootCommand(String commandText) { super(commandText); this._cmdTxt = commandText; } + + public static boolean executeRootCmd(String cmd) { + + try { + RootCommand c = new RootCommand(cmd); + if (c.execute() == 0) { + return true; + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error executing \"" + cmd + "\"", e); + return false; + } + } + @Override public int execute() throws Exception { + if (this._cmdTxt == null) { + return EXITCODE_INVALID_INPUT; + } + Process su = Runtime.getRuntime().exec("su"); DataOutputStream stdin = new DataOutputStream(su.getOutputStream()); InputStream os = su.getInputStream(); InputStream es = su.getErrorStream(); - if (this._cmdTxt != null) { - - Utils.logDebug("SU:EXEC: " + this._cmdTxt); + Utils.logDebug("SU:EXEC: " + this._cmdTxt); - this._cmdTxt += " > " + Commons.getTempOutFile(); - - stdin.writeBytes(this._cmdTxt + "\n"); - stdin.flush(); - } + String wrappedCmd = String.format(CMD_WRAPPING, this._cmdTxt); + + stdin.writeBytes(wrappedCmd + "\n"); + stdin.flush(); StringBuilder sb = new StringBuilder(); sb.append(getStringFromStream(es)); sb.append(getStringFromStream(os)); - this._cmdOut = sb.toString(); - - stdin.writeBytes("exit\n"); - stdin.flush(); - int res = su.waitFor(); // re-read the output, in case it was empty when first tried sb.append(getStringFromStream(es)); sb.append(getStringFromStream(os)); + this._cmdOut = sb.toString(); + Utils.logDebug("OUT: " + getOutput()); return res; } + + public int testRootAccess() throws Exception { - @Override - public String getOutput() { + Process su = Runtime.getRuntime().exec("su"); - String[] lastOut = Utils.readFileLines(Commons.getTempOutFile()); - if (lastOut == null) { - return this._cmdOut; - } + DataOutputStream stdin = new DataOutputStream(su.getOutputStream()); - String fout = ""; + Utils.logDebug("Testing root access: executing simple \"su\""); + stdin.writeBytes("exit\n"); + stdin.flush(); - for (String s : lastOut) { - fout += s + "\n"; - } + int res = su.waitFor(); - return fout; + Utils.logDebug("Simple \"su\" exitcode: " + res); + + return res; } diff --git a/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java b/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java index fbeb719..f232ac7 100644 --- a/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java +++ b/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java @@ -5,6 +5,8 @@ import java.io.InputStream; public class ShellCommand { + public static final int EXITCODE_INVALID_INPUT = -9; + protected String _cmdOut = ""; protected String _cmdTxt = ""; @@ -15,12 +17,13 @@ public class ShellCommand { public int execute() throws Exception { if (this._cmdTxt == null) { - return -9; + return EXITCODE_INVALID_INPUT; } Utils.logDebug("EXEC: " + this._cmdTxt); Process cmd = Runtime.getRuntime().exec(this._cmdTxt); + InputStream os = cmd.getInputStream(); InputStream es = cmd.getErrorStream(); @@ -47,6 +50,11 @@ public class ShellCommand { protected String getStringFromStream(InputStream s) throws IOException { + java.util.Scanner sc = new java.util.Scanner(s,"UTF-8").useDelimiter("\\A"); + return sc.hasNext() ? sc.next() : ""; + + /* + StringBuilder sb = new StringBuilder(); while ((s.available() > 0)) { int b = s.read(); @@ -57,7 +65,7 @@ public class ShellCommand { } } - return sb.toString(); + return sb.toString();*/ } @@ -65,17 +73,6 @@ public class ShellCommand { return this._cmdOut; - /* - * String[] lastOut = Utils.readFileLines(Commons.getTempOutFile()); if - * (lastOut == null){ return this._cmdOut; } - * - * String fout = ""; - * - * for (String s : lastOut){ fout += s + "\n"; } - * - * return fout; - */ - } } diff --git a/app/src/fil/libre/repwifiapp/helpers/Utils.java b/app/src/fil/libre/repwifiapp/helpers/Utils.java index 8cd90bf..ad10c1a 100644 --- a/app/src/fil/libre/repwifiapp/helpers/Utils.java +++ b/app/src/fil/libre/repwifiapp/helpers/Utils.java @@ -63,63 +63,50 @@ public class Utils { Log.d(APP_NAME, msg); } - public static boolean writeFile(String filePath, String text, boolean overwrite) { - - FileWriter writer = null; - boolean retval = false; + public static boolean writeFileLines(String filePath, String[] lines, boolean overwrite) { - try { + if (lines == null) { + return false; + } - writer = new FileWriter(filePath, (!overwrite)); - writer.write(text); + if (lines.length == 0) { + return true; + } - retval = true; + StringBuilder sb = new StringBuilder(); - } catch (Exception e) { - _lastException = e; - retval = false; - } finally { + for (String l : lines) { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - logError("error while closing filewriter", e); - } + if (l == null) { + return false; } + sb.append(l + "\n"); } - return retval; + return writeFile(filePath, sb.toString(), overwrite); } - public static boolean writeFileLines(String filePath, String[] lines, boolean overwrite) { + public static boolean writeFile(String filePath, String content, boolean overwrite) { - if (lines == null) { + if (content == null) { return false; } FileWriter writer = null; - boolean retval = false; try { writer = new FileWriter(filePath, (!overwrite)); + writer.write(content); - if (lines.length == 0) { - writer.write(""); - } - - for (String l : lines) { - writer.write(l + "\n"); - } - - retval = true; + return true; } catch (Exception e) { _lastException = e; - retval = false; + return false; + } finally { if (writer != null) { @@ -132,8 +119,6 @@ public class Utils { } - return retval; - } public static String[] readFileLines(String filePath) { @@ -152,7 +137,6 @@ public class Utils { BufferedReader bufr = null; List<String> lines = new ArrayList<String>(); - String[] ret = null; try { @@ -165,11 +149,13 @@ public class Utils { } String[] ar = new String[lines.size()]; - ret = lines.toArray(ar); + + return lines.toArray(ar); } catch (Exception e) { logError("Error while reading file " + filePath, e); - ret = null; + return null; + } finally { try { if (bufr != null) { @@ -187,10 +173,61 @@ public class Utils { } } - return ret; - } + public static String readFile(String filePath){ + + if (filePath == null) { + return null; + } + + File f = new File(filePath); + if (!f.exists()) { + logError("File doesn't exist: " + filePath); + return null; + } + + FileReader fr = null; + BufferedReader bufr = null; + + StringBuilder sb = new StringBuilder(); + + try { + + fr = new FileReader(filePath); + bufr = new BufferedReader(fr); + String line = ""; + + while ((line = bufr.readLine()) != null) { + sb.append(line); + sb.append("\n"); + } + + return sb.toString(); + + } catch (Exception e) { + logError("Error while reading file " + filePath, e); + return null; + + } finally { + try { + if (bufr != null) { + bufr.close(); + } + } catch (IOException ex) { + logError("error while closing filereader", ex); + } + try { + if (fr != null) { + fr.close(); + } + } catch (IOException exc) { + logError("error while closing filereader", exc); + } + } + + } + public static long daysToMilliseconds(int days) { return (days * MILLIS_IN_DAY); } @@ -199,4 +236,120 @@ public class Utils { return (milliseconds / MILLIS_IN_DAY); } + public static boolean dumpLogcatToFile(String filePath) { + + if (filePath == null) { + return false; + } + + try { + + String cmd1 = "logcat -d | grep " + APP_NAME + ">" + filePath; + String cmd2 = "logcat -d | grep " + Commons.getContext().getPackageName() + ">>" + + filePath; + String SEP_LOG = "\n\n---------- [REPWIFI_LOG_SEPARATOR] ----------\n\n"; + + RootCommand c1 = new RootCommand(cmd1); + RootCommand c2 = new RootCommand(cmd2); + + if (c1.execute() != 0) { + return false; + } + + if (!writeFile(filePath, SEP_LOG, false)) { + return false; + } + + if (c2.execute() != 0) { + return false; + } + + return true; + + } catch (Exception e) { + logError("Exception during log dump.", e); + return false; + } + + } + + public static String netmaskIntToString(int mask) { + + if (mask < 8 || mask > 32) { + return null; + } + + StringBuilder sb = new StringBuilder(32); + StringBuilder sb2 = new StringBuilder(15); + + for (int i = 0; i < mask; i++) { + sb.append("1"); + } + + for (int i = 0; i < 32 - mask; i++) { + sb.append("0"); + } + + for (int i = 0; i < 3; i++) { + String bitString = sb.substring((i * 8), (i * 8) + 8); + int ibyte = Integer.parseInt(bitString, 2); + sb2.append(ibyte); + sb2.append("."); + } + String bitString = sb.substring(24, 32); + int ibyte = Integer.parseInt(bitString, 2); + sb2.append(ibyte); + + return sb2.toString(); + + } + + public static int netmaskStringToInt(String mask) { + + if (mask == null) { + return -1; + } + + String[] octs = mask.split("\\."); + if (octs.length != 4) { + return -1; + } + + int intmask = 0; + boolean prevIsZero = false; + for (String o : octs) { + + int intval = 0; + + try { + intval = Integer.parseInt(o, 10); + } catch (NumberFormatException e) { + return -1; + } + + String b = Integer.toBinaryString(intval); + if (b.length() != 8 && b.contains("1")) { + //invalid mask! has ones after a zero + return -1; + } + for (int i = 0; i < b.length(); i++) { + if (b.charAt(i) == '0') { + prevIsZero = true; + + } else if (prevIsZero) { + // invalid mask + return -1; + + } else { + intmask += 1; + } + + } + + } + + return intmask; + + } + } diff --git a/app/src/fil/libre/repwifiapp/helpers/WpaCli.java b/app/src/fil/libre/repwifiapp/helpers/WpaCli.java new file mode 100644 index 0000000..8bd6561 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/helpers/WpaCli.java @@ -0,0 +1,263 @@ +package fil.libre.repwifiapp.helpers; + +public abstract class WpaCli { + + private static final int SCAN_WAIT_INTERVAL = 3; + private static final String BASE_COMMAND = "wpa_cli -p" + WpaSupplicant.SOCKET_DIR + " -P" + + WpaSupplicant.PID_FILE + " -i" + WpaSupplicant.INTERFACE_NAME; + + public static String createNetworkGetId() { + + try { + + RootCommand su = new RootCommand(BASE_COMMAND + " add_network"); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out == null || out.trim().equals("")) { + return null; + } else { + return out.replace("\n", ""); + } + } else { + return null; + } + + } catch (Exception e) { + Utils.logError("Error while creating network", e); + return null; + } + + } + + public static boolean setNetworkSSID(String ssid, String networkID) { + + try { + + // needs root (wpa_cli) + RootCommand su = new RootCommand(BASE_COMMAND + " set_network " + networkID + + " ssid '\"" + ssid + "\"'"); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while setting network SSID", e); + return false; + } + + } + + public static boolean setNetworkPSK(AccessPointInfo info, String networkID) { + + try { + + // needs root (wpa_cli) + + String cmdSetPass = null; + if (info.needsPassword()) { + cmdSetPass = BASE_COMMAND + " set_network " + networkID + " psk '\"" + + info.getPassword() + "\"'"; + } else { + cmdSetPass = BASE_COMMAND + " set_network " + networkID + " key_mgmt NONE"; + } + + RootCommand su = new RootCommand(cmdSetPass); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while setting network PSK", e); + return false; + } + + } + + public static boolean setNetworkScanSSID(String networkID) { + + try { + + // needs root (wpa_cli) + RootCommand su = new RootCommand(BASE_COMMAND + " set_network " + networkID + + " scan_ssid 1"); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while setting network SSID", e); + return false; + } + } + + public static boolean selectNetwork(String networkID) { + + try { + + // needs root (wpa_cli) + RootCommand su = new RootCommand(BASE_COMMAND + " select_network " + networkID); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while selecting network", e); + return false; + } + + } + + public static boolean enableNetwork(String networkID) { + + try { + + // needs root (wpa_cli) + + RootCommand su = new RootCommand(BASE_COMMAND + " enable_network " + networkID); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while enabling network", e); + return false; + } + + } + + public static boolean scanNetworks() { + + // needs root (for wpa_supplicant and wpa_cli) + return RootCommand.executeRootCmd(BASE_COMMAND + + " scan; if [ $? -ne 0 ]; then exit 1; fi; sleep " + SCAN_WAIT_INTERVAL); + + } + + public static String getScanResults() { + + try { + + RootCommand su = new RootCommand(BASE_COMMAND + + " scan_results; if [ $? -ne 0 ]; then exit 1; fi "); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out == null || out.trim().equals("")) { + return null; + } else { + return out; + } + } else { + return null; + } + + } catch (Exception e) { + Utils.logError("Error while executing wpa_cli status", e); + return null; + } + + /* + * // needs root (for wpa_supplicant and wpa_cli) boolean res = + * RootCommand.executeRootCmd(); if (!res) { return false; } return res; + */ + + } + + /*** + * returns null if unable to determine connection status for any reason. + */ + public static ConnectionStatus getConnectionStatus() { + + Utils.logDebug("called getConnecitonStatus()"); + if (!WpaSupplicant.isRunning()) { + // wpa_supplicant is not running. + // unable to determine status. + Utils.logDebug("wpa not running, cannot get connection status."); + return null; + + } + + try { + + RootCommand su = new RootCommand(BASE_COMMAND + " status"); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out == null || out.trim().equals("")) { + return null; + } else { + return ConnectionStatus.parseWpaCliOutput(out); + } + } else { + return null; + } + + } catch (Exception e) { + Utils.logError("Error while executing wpa_cli status", e); + return null; + } + + } + + public static boolean disconnect() { + + // needs root (for wpa_cli) + + if (!WpaSupplicant.isRunning()) { + return true; + } + + try { + + RootCommand su = new RootCommand(BASE_COMMAND + " disconnect"); + if (su.execute() == 0) { + String out = su.getOutput(); + if (out != null && out.trim().replace("\n", "").equals("OK")) { + return true; + } else { + return false; + } + } else { + return false; + } + + } catch (Exception e) { + Utils.logError("Error while enabling network", e); + return false; + } + } + +} diff --git a/app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java b/app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java new file mode 100644 index 0000000..1dfe449 --- /dev/null +++ b/app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java @@ -0,0 +1,65 @@ +package fil.libre.repwifiapp.helpers; + + +public abstract class WpaSupplicant { + + public static final String INTERFACE_NAME = "wlan0"; + public static final String WORKDIR = "/data/misc/wifi"; + public static final String PID_FILE = WORKDIR + "/pidfile"; + public static final String SOCKET_DIR = WORKDIR + "/sockets/"; + public static final String SOFTAP_FILE = WORKDIR + "/softap.conf"; + public static final String P2P_CONF = WORKDIR + "/p2p_supplicant.conf"; + public static final String WPA_CONF = WORKDIR + "/wpa_supplicant.conf"; + public static final String ENTROPY_FILE = WORKDIR + "/entropy.bin"; + public static final String OVERLAY_FILE = "/system/etc/wifi/wpa_supplicant_overlay.conf"; + + protected static final String BASE_COMMNAD = "wpa_supplicant -B -dd -i" + INTERFACE_NAME + " -C" + SOCKET_DIR + " -P" + PID_FILE + + " -I" + OVERLAY_FILE + " -e" + ENTROPY_FILE; + + public static boolean start() { + + Utils.logDebug("startWpaSupplicant():"); + + // needs root (for wpa_supplicant) + if (RootCommand.executeRootCmd(BASE_COMMNAD)) { + return true; + } else { + Utils.logDebug("Failed to start wpa"); + return false; + } + + } + + public static boolean kill(){ + return RootCommand.executeRootCmd("killall -SIGINT wpa_supplicant"); + } + + public static boolean isRunning() { + + boolean retval = false; + + try { + + RootCommand su = new RootCommand("pidof wpa_supplicant"); + if (su.execute() == 0) { + + if (su.getOutput().trim().equals("")) { + retval = false; + } else { + retval = true; + } + + } else { + retval = false; + } + + } catch (Exception e) { + Utils.logError("Exception during isWpaSupplicantRunning()", e); + retval = false; + } + + return retval; + + } + +} |