From 2495d8032eb6839a55080b79ac818383c2f75b79 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Fri, 5 May 2017 01:02:16 +0200 Subject: Import unversioned prototype --- app/CMakeLists.txt | 54 +++++++ app/build.gradle | 49 +++++++ app/proguard-rules.pro | 1 + .../androidTest/java/org/pacien/tincapp/.gitkeep | 0 app/src/main/AndroidManifest.xml | 35 +++++ app/src/main/c/exec.c | 34 +++++ .../pacien/tincapp/activities/BaseActivity.java | 71 +++++++++ .../pacien/tincapp/activities/StartActivity.java | 82 +++++++++++ .../java/org/pacien/tincapp/commands/Command.java | 67 +++++++++ .../java/org/pacien/tincapp/commands/Executor.java | 44 ++++++ .../pacien/tincapp/commands/PermissionFixer.java | 34 +++++ .../java/org/pacien/tincapp/commands/Tinc.java | 60 ++++++++ .../java/org/pacien/tincapp/commands/Tincd.java | 28 ++++ .../java/org/pacien/tincapp/context/AppInfo.java | 42 ++++++ .../java/org/pacien/tincapp/context/AppPaths.java | 75 ++++++++++ .../org/pacien/tincapp/service/TincVpnService.java | 51 +++++++ .../tincapp/service/VpnInterfaceConfigurator.java | 81 +++++++++++ .../java/org/pacien/tincapp/util/Function.java | 28 ++++ app/src/main/res/drawable/ic_help_primary_24dp.xml | 9 ++ app/src/main/res/icon.png | Bin 0 -> 13933 bytes app/src/main/res/icon.svg | 1 + app/src/main/res/layout/base.xml | 47 ++++++ app/src/main/res/layout/dialog_frame.xml | 11 ++ app/src/main/res/layout/page_start.xml | 43 ++++++ app/src/main/res/menu/menu_base.xml | 14 ++ app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1103 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 777 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 1400 bytes app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 2312 bytes app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 3425 bytes app/src/main/res/values-v21/styles.xml | 8 ++ app/src/main/res/values-w820dp/dimens.xml | 3 + app/src/main/res/values/colors.xml | 7 + app/src/main/res/values/dimens.xml | 9 ++ app/src/main/res/values/strings.xml | 33 +++++ app/src/main/res/values/styles.xml | 16 +++ build.gradle | 24 ++++ gradle.properties | 17 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 +++++++++++++++++++++ gradlew.bat | 90 ++++++++++++ settings.gradle | 1 + 43 files changed, 1335 insertions(+) create mode 100644 app/CMakeLists.txt create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/org/pacien/tincapp/.gitkeep create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/c/exec.c create mode 100644 app/src/main/java/org/pacien/tincapp/activities/BaseActivity.java create mode 100644 app/src/main/java/org/pacien/tincapp/activities/StartActivity.java create mode 100644 app/src/main/java/org/pacien/tincapp/commands/Command.java create mode 100644 app/src/main/java/org/pacien/tincapp/commands/Executor.java create mode 100644 app/src/main/java/org/pacien/tincapp/commands/PermissionFixer.java create mode 100644 app/src/main/java/org/pacien/tincapp/commands/Tinc.java create mode 100644 app/src/main/java/org/pacien/tincapp/commands/Tincd.java create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppInfo.java create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppPaths.java create mode 100644 app/src/main/java/org/pacien/tincapp/service/TincVpnService.java create mode 100644 app/src/main/java/org/pacien/tincapp/service/VpnInterfaceConfigurator.java create mode 100644 app/src/main/java/org/pacien/tincapp/util/Function.java create mode 100644 app/src/main/res/drawable/ic_help_primary_24dp.xml create mode 100644 app/src/main/res/icon.png create mode 100644 app/src/main/res/icon.svg create mode 100644 app/src/main/res/layout/base.xml create mode 100644 app/src/main/res/layout/dialog_frame.xml create mode 100644 app/src/main/res/layout/page_start.xml create mode 100644 app/src/main/res/menu/menu_base.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..d115cb6 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.4.1) +include(ExternalProject) + +set(xCONFIG + "CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN}${CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN} ${CMAKE_C_COMPILE_OPTIONS_TARGET}${CMAKE_C_COMPILER_TARGET}" + "LD=${CMAKE_LINKER}" + "AR=${CMAKE_AR}" + "RANLIB=${CMAKE_RANLIB}" + "CFLAGS=${CMAKE_C_FLAGS} ${CMAKE_C_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT}" + "LDFLAGS=${CMAKE_STATIC_LINKER_FLAGS} ${CMAKE_C_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT}" + "--host=${CMAKE_C_COMPILER_TARGET}" +) + +if(${ANDROID_ABI} STREQUAL "mips64") + list(APPEND xCONFIG --disable-asm) +endif() + +ExternalProject_Add(lzo + URL http://files.pacien.net/tmp/lzo-2.10.tar.gz + URL_HASH SHA1=4924676a9bae5db58ef129dc1cebce3baa3c4b5d + CONFIGURE_COMMAND /configure ${xCONFIG} --disable-shared + BUILD_COMMAND make -j4 + INSTALL_COMMAND make install DESTDIR=${CMAKE_CURRENT_BINARY_DIR} && + rm -r +) + +ExternalProject_Add(libressl + URL http://files.pacien.net/tmp/libressl-2.5.4.tar.gz + URL_HASH SHA256=107a5b522fbb8318d4c3be668075e5e607296f0a9255d71674caa94571336efa + CONFIGURE_COMMAND /configure ${xCONFIG} --disable-shared + BUILD_COMMAND make -j4 -C crypto + INSTALL_COMMAND make -C crypto install DESTDIR=${CMAKE_CURRENT_BINARY_DIR} && + make -C include install DESTDIR=${CMAKE_CURRENT_BINARY_DIR} && + rm -r +) + +ExternalProject_Add(tinc + DEPENDS lzo libressl + URL http://files.pacien.net/tmp/tinc-1.1pre15-SNAPSHOT.tar.gz + CONFIGURE_COMMAND autoreconf -fsi && + /configure ${xCONFIG} + --with-openssl=${CMAKE_CURRENT_BINARY_DIR}/usr/local + --with-lzo=${CMAKE_CURRENT_BINARY_DIR}/usr/local + --disable-curses + --disable-readline + BUILD_COMMAND make -j4 -C src + INSTALL_COMMAND make -C src install DESTDIR=${CMAKE_CURRENT_BINARY_DIR} && + ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/usr/local/sbin/tinc ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libtinc.so && + ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/usr/local/sbin/tincd ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libtincd.so && + rm -r +) + +add_library(exec SHARED src/main/c/exec.c) +add_dependencies(exec tinc) diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..33514ea --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,49 @@ +apply plugin: 'com.android.application' +apply plugin: 'me.tatarka.retrolambda' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.0' + defaultConfig { + applicationId "org.pacien.tincapp" + minSdkVersion 21 + targetSdkVersion 25 + versionCode 1 + versionName "0.1-preview" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + + compile 'com.android.support:appcompat-v7:25.3.1' + compile 'com.android.support:design:25.3.1' + compile 'com.android.support:support-v4:25.3.1' + compile 'com.android.support:recyclerview-v7:25.3.1' + compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4' + + compile('org.apache.commons:commons-configuration2:2.1.1') { + exclude group: 'commons-logging', module: 'commons-logging' + } + compile('commons-beanutils:commons-beanutils:1.9.3') { + exclude group: 'commons-logging', module: 'commons-logging' + } + + compile 'com.annimon:stream:1.1.5' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f795eae --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1 @@ +-dontwarn org.apache.commons.** diff --git a/app/src/androidTest/java/org/pacien/tincapp/.gitkeep b/app/src/androidTest/java/org/pacien/tincapp/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2822d37 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/c/exec.c b/app/src/main/c/exec.c new file mode 100644 index 0000000..fdaec0f --- /dev/null +++ b/app/src/main/c/exec.c @@ -0,0 +1,34 @@ +#include +#include +#include + +static inline const char **to_string_array(JNIEnv *env, jobjectArray ja) { + const int len = (*env)->GetArrayLength(env, ja); + const char **ca = calloc((size_t) len + 1, sizeof(char *)); + + for (int i = 0; i < len; ++i) { + jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, ja, i); + ca[i] = (*env)->GetStringUTFChars(env, jstr, NULL); + } + + ca[len] = NULL; + return ca; +} + +static inline void exec(const char **argcv) { + execv(argcv[0], (char *const *) argcv); + exit(1); +} + +JNIEXPORT jint JNICALL +Java_org_pacien_tincapp_commands_Executor_forkExec(JNIEnv *env, jclass class, jobjectArray argcv) { + pid_t pid = fork(); + switch (pid) { + case 0: + exec(to_string_array(env, argcv)); + return 0; + + default: + return pid; + } +} diff --git a/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.java b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.java new file mode 100644 index 0000000..0e6cb95 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.java @@ -0,0 +1,71 @@ +package org.pacien.tincapp.activities; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; + +import org.pacien.tincapp.BuildConfig; +import org.pacien.tincapp.R; +import org.pacien.tincapp.context.AppInfo; + +/** + * @author pacien + */ +public abstract class BaseActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.base); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + } + + @Override + public boolean onCreateOptionsMenu(Menu m) { + getMenuInflater().inflate(R.menu.menu_base, m); + return true; + } + + public void aboutDialog(MenuItem i) { + new AlertDialog.Builder(this) + .setTitle(BuildConfig.APPLICATION_ID) + .setMessage(getResources().getString(R.string.app_short_desc) + "\n\n" + + getResources().getString(R.string.app_copyright) + " " + + getResources().getString(R.string.app_license) + "\n\n" + + AppInfo.all(getResources())) + .setNeutralButton(R.string.action_open_project_website, (dialog, which) -> openWebsite(R.string.app_website_url)) + .setPositiveButton(R.string.action_close, (dialog, which) -> { /* nop */ }) + .show(); + } + + protected ViewGroup getContentView() { + return (ViewGroup) findViewById(R.id.main_content); + } + + protected void openWebsite(@StringRes int url) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().getString(url)))); + } + + protected void notify(@StringRes int msg) { + Snackbar.make(findViewById(R.id.activity_base), msg, Snackbar.LENGTH_LONG).show(); + } + + protected void copyIntoClipboard(String label, String str) { + ClipboardManager c = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + c.setPrimaryClip(ClipData.newPlainText(label, str)); + notify(R.string.message_text_copied); + } + +} diff --git a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.java b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.java new file mode 100644 index 0000000..e469fa0 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.java @@ -0,0 +1,82 @@ +package org.pacien.tincapp.activities; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; + +import org.pacien.tincapp.R; +import org.pacien.tincapp.commands.PermissionFixer; +import org.pacien.tincapp.context.AppPaths; +import org.pacien.tincapp.service.TincVpnService; + +/** + * @author pacien + */ +public class StartActivity extends BaseActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getLayoutInflater().inflate(R.layout.page_start, getContentView()); + } + + @Override + protected void onActivityResult(int request, int result, Intent data) { + notify(result == RESULT_OK ? R.string.message_vpn_permissions_granted : R.string.message_vpn_permissions_denied); + } + + public void requestVpnPermission(View v) { + Intent askPermIntent = TincVpnService.prepare(this); + + if (askPermIntent != null) + startActivityForResult(askPermIntent, 0); + else + onActivityResult(0, RESULT_OK, null); + } + + public void startVpnDialog(View v) { + final EditText i = new EditText(this); + i.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + i.setHint(R.string.field_net_name); + + @SuppressLint("InflateParams") + ViewGroup vg = (ViewGroup) getLayoutInflater().inflate(R.layout.dialog_frame, null); + vg.addView(i); + + new AlertDialog.Builder(this) + .setTitle(R.string.title_connect_to_network) + .setView(vg) + .setPositiveButton(R.string.action_connect, (dialog, which) -> startVpn(i.getText().toString())) + .setNegativeButton(R.string.action_close, (dialog, which) -> { /* nop */ }) + .show(); + } + + public void confDirDialog(View v) { + String confDir = AppPaths.confDir(this).getPath(); + + new AlertDialog.Builder(this) + .setTitle(R.string.title_tinc_config_dir) + .setMessage(confDir) + .setNeutralButton(R.string.action_fix_perms, (dialog, which) -> fixPerms()) + .setNegativeButton(R.string.action_copy, + (dialog, which) -> copyIntoClipboard(getResources().getString(R.string.title_tinc_config_dir), confDir)) + .setPositiveButton(R.string.action_close, (dialog, which) -> { /* nop */ }) + .show(); + } + + private void startVpn(String netName) { + startService(new Intent(this, TincVpnService.class) + .putExtra(TincVpnService.INTENT_EXTRA_NET_NAME, netName)); + } + + private void fixPerms() { + boolean ok = PermissionFixer.makePrivateDirsPublic(getApplicationContext()); + notify(ok ? R.string.message_perms_fixed : R.string.message_perms_fix_failure); + } + +} diff --git a/app/src/main/java/org/pacien/tincapp/commands/Command.java b/app/src/main/java/org/pacien/tincapp/commands/Command.java new file mode 100644 index 0000000..28ff226 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/commands/Command.java @@ -0,0 +1,67 @@ +package org.pacien.tincapp.commands; + +import com.annimon.stream.Collectors; +import com.annimon.stream.Optional; +import com.annimon.stream.Stream; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * @author pacien + */ +class Command { + + static private class Option { + final String key; + final Optional val; + + Option(String key, String val) { + this.key = key; + this.val = Optional.ofNullable(val); + } + + @Override + public String toString() { + return val.isPresent() ? "--" + key + "=" + val.get() : "--" + key; + } + } + + final private String cmd; + final private List