commit fea1fbbad5f49f0a413ee563fb5defa2c98da04f Author: Bandie Date: Mon May 25 16:11:33 2020 +0200 Project commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..542fab9 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Yipanic \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/bandie.xml b/.idea/dictionaries/bandie.xml new file mode 100644 index 0000000..38863b4 --- /dev/null +++ b/.idea/dictionaries/bandie.xml @@ -0,0 +1,9 @@ + + + + bandie + passcode + yipanic + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..5cd135a --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..37a7509 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..31473b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2017, Bandie +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3904d74 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Yipanic +This appilcation sends a JSON to an API with the intent to remote control your computer or infrastructure in terms of panic. + +The app can be secured by a passcode. + +## What the app sends + +```json +{ + "key": string, + "secret": string, + "cmd": "(lock|shutdown|panic|infraShutdown|infraPanic)" +} +``` + +`cmd` requires one of `lock`, `shutdown`, ... + + +## What answers the app expect + +```json +{ + "access": (true|false), + "error": int +} +``` + + +At the moment the following error codes are defined: + +``` +0 - OK +1 - Command not set +``` + + +## Example backend + +See `example/index.php`. + + +### What is ding? + +See [ding](https://git.chaospott.de/Bandie/ding/). diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..c57406f --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + applicationId "org.bandie.yipanic" + minSdkVersion 23 + targetSdkVersion 29 + versionCode 1 + versionName "1.1" + testFunctionalTest = false + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'com.android.volley:volley:1.1.1' + implementation 'androidx.preference:preference:1.1.1' + implementation 'androidx.security:security-crypto:1.0.0-rc02' + implementation 'com.google.android.material:material:1.1.0' +} diff --git a/app/lint.xml b/app/lint.xml new file mode 100644 index 0000000..6ee0e0d --- /dev/null +++ b/app/lint.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/release/app-release.apk b/app/release/app-release.apk new file mode 100644 index 0000000..6f1e732 Binary files /dev/null and b/app/release/app-release.apk differ diff --git a/app/release/output.json b/app/release/output.json new file mode 100644 index 0000000..12e1198 --- /dev/null +++ b/app/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6fc282b --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..5ff555f Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/org/bandie/yipanic/Command.java b/app/src/main/java/org/bandie/yipanic/Command.java new file mode 100644 index 0000000..239634b --- /dev/null +++ b/app/src/main/java/org/bandie/yipanic/Command.java @@ -0,0 +1,134 @@ +package org.bandie.yipanic; + +import android.content.Context; +import android.util.Log; +import android.view.View; + +import androidx.security.crypto.EncryptedSharedPreferences; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.JsonObjectRequest; +import com.google.android.material.snackbar.Snackbar; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +class Command { + private final Snackbar sbOk, sbNotSet, sbAccessDenied, sbFailed, sbNoServer; + private String server, k, s; + + Command(View view, Context context) { + this.sbOk = Snackbar.make(view, "Sent. :)", 3000); + this.sbNotSet = Snackbar.make(view, "Command not set. :/", 3000); + this.sbAccessDenied = Snackbar.make(view, "Access denied. >:(", 3000); + this.sbFailed = Snackbar.make(view, "Failed. :C", 3000); + this.sbNoServer = Snackbar.make(view, "No server configured! :o", 3000); + + try { + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + context, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + this.server = sharedPreferences.getString("server", null); + this.k = sharedPreferences.getString("key", null); + this.s = sharedPreferences.getString("secret", null); + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + } + } + + private JsonObjectRequest requestHandler(String cmd) { + JSONObject json = new JSONObject(); + try { + json.put("key", this.k); + json.put("secret", this.s); + json.put("cmd", cmd); + } catch (JSONException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + } + if (this.server == null) { + sbNoServer.show(); + return null; + } + return new JsonObjectRequest + (Request.Method.POST, this.server, json, new Response.Listener() { + + @Override + public void onResponse(JSONObject response) { + try { + if (response.getBoolean("access")) { + switch (response.getInt("error")) { + case 0: + sbOk.show(); + break; + case 1: + sbNotSet.show(); + break; + case 2: + //Password required + break; + case 4: + //Password OK + break; + } + } else { + sbAccessDenied.show(); + } + + } catch (JSONException e) { + if (e.getMessage() != null) + Log.e("Yip", e.getMessage()); + else + Log.e("Yip", "[ No exception message ]"); + sbFailed.show(); + } + } + }, new Response.ErrorListener() { + + @Override + public void onErrorResponse(VolleyError e) { + if (e.getMessage() != null) + Log.e("Yip", e.getMessage()); + else + Log.e("Yip", "[ No exception message ]"); + sbFailed.show(); + } + }); + } + + JsonObjectRequest lock() { + return requestHandler("lock"); + } + + JsonObjectRequest shutdown() { + return requestHandler("shutdown"); + } + + JsonObjectRequest panic() { + return requestHandler("panic"); + } + + JsonObjectRequest infraShutdown() { + return requestHandler("infraShutdown"); + } + + JsonObjectRequest infraPanic() { + return requestHandler("infraPanic"); + } + +} diff --git a/app/src/main/java/org/bandie/yipanic/CommandActivity.java b/app/src/main/java/org/bandie/yipanic/CommandActivity.java new file mode 100644 index 0000000..fe8a824 --- /dev/null +++ b/app/src/main/java/org/bandie/yipanic/CommandActivity.java @@ -0,0 +1,212 @@ +package org.bandie.yipanic; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageButton; +import android.widget.Switch; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.NavUtils; + +import com.android.volley.toolbox.JsonObjectRequest; +import com.android.volley.toolbox.Volley; + + +public class CommandActivity extends AppCompatActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.command_activity); + + ImageButton b = findViewById(R.id.btnShutdown); + b.setEnabled(false); + b = findViewById(R.id.btnPanic); + b.setEnabled(false); + b = findViewById(R.id.btnInfraShutdown); + b.setEnabled(false); + b = findViewById(R.id.btnInfraPanic); + b.setEnabled(false); + + Switch s = findViewById(R.id.swSecShutdown1); + s.setChecked(false); + s = findViewById(R.id.swSecShutdown2); + s.setChecked(false); + s = findViewById(R.id.swSecPanic1); + s.setChecked(false); + s = findViewById(R.id.swSecPanic2); + s.setChecked(false); + s = findViewById(R.id.swSecPanic3); + s.setChecked(false); + s = findViewById(R.id.swSecInfraShutdown1); + s.setChecked(false); + s = findViewById(R.id.swSecInfraShutdown2); + s.setChecked(false); + s = findViewById(R.id.swSecInfraPanic1); + s.setChecked(false); + s = findViewById(R.id.swSecInfraPanic2); + s.setChecked(false); + s = findViewById(R.id.swSecInfraPanic3); + s.setChecked(false); + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + System.out.println(item.getItemId()); + switch (item.getItemId()) { + case 16908332: + case R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onPause() { + super.onPause(); + this.finish(); + } + + public void sendLockCmd(View view) { + Command c = new Command(view, getApplicationContext()); + JsonObjectRequest send = c.lock(); + if (send != null) + Volley.newRequestQueue(this).add(send); + } + + public void sendShutdownCmd(View view) { + Command c = new Command(view, getApplicationContext()); + JsonObjectRequest send = c.shutdown(); + if (send != null) + Volley.newRequestQueue(this).add(send); + } + + public void sendPanicCmd(View view) { + Command c = new Command(view, getApplicationContext()); + JsonObjectRequest send = c.panic(); + if (send != null) + Volley.newRequestQueue(this).add(send); + } + + public void sendInfraShutdownCmd(View view) { + Command c = new Command(view, getApplicationContext()); + JsonObjectRequest send = c.infraShutdown(); + if (send != null) + Volley.newRequestQueue(this).add(send); + } + + public void sendInfraPanicCmd(View view) { + Command c = new Command(view, getApplicationContext()); + JsonObjectRequest send = c.infraPanic(); + if (send != null) + Volley.newRequestQueue(this).add(send); + } + + public void switchShutdown(View view) { + final Switch s = findViewById(view.getId()); + Switch s1 = findViewById(R.id.swSecShutdown1); + Switch s2 = findViewById(R.id.swSecShutdown2); + ImageButton b = findViewById(R.id.btnShutdown); + if (s1.isChecked() && s2.isChecked()) + b.setEnabled(true); + else + b.setEnabled(false); + + if (s.isChecked()) { + Handler h = new Handler(); + h.postDelayed(new Runnable() { + @Override + public void run() { + ImageButton b = findViewById(R.id.btnShutdown); + s.setChecked(false); + b.setEnabled(false); + } + }, 10000); + } + } + + public void switchPanic(View view) { + final Switch s = findViewById(view.getId()); + Switch s1 = findViewById(R.id.swSecPanic1); + Switch s2 = findViewById(R.id.swSecPanic2); + Switch s3 = findViewById(R.id.swSecPanic3); + ImageButton b = findViewById(R.id.btnPanic); + if (s1.isChecked() && s2.isChecked() && s3.isChecked()) + b.setEnabled(true); + else + b.setEnabled(false); + + if (s.isChecked()) { + Handler h = new Handler(); + h.postDelayed(new Runnable() { + @Override + public void run() { + ImageButton b = findViewById(R.id.btnPanic); + s.setChecked(false); + b.setEnabled(false); + } + }, 10000); + } + } + + public void switchInfraShutdown(View view) { + final Switch s = findViewById(view.getId()); + Switch s1 = findViewById(R.id.swSecInfraShutdown1); + Switch s2 = findViewById(R.id.swSecInfraShutdown2); + ImageButton b = findViewById(R.id.btnInfraShutdown); + if (s1.isChecked() && s2.isChecked()) + b.setEnabled(true); + else + b.setEnabled(false); + + if (s.isChecked()) { + Handler h = new Handler(); + h.postDelayed(new Runnable() { + @Override + public void run() { + ImageButton b = findViewById(R.id.btnInfraShutdown); + s.setChecked(false); + b.setEnabled(false); + } + }, 10000); + } + } + + public void switchInfraPanic(View view) { + final Switch s = findViewById(view.getId()); + Switch s1 = findViewById(R.id.swSecInfraPanic1); + Switch s2 = findViewById(R.id.swSecInfraPanic2); + Switch s3 = findViewById(R.id.swSecInfraPanic3); + ImageButton b = findViewById(R.id.btnInfraPanic); + if (s1.isChecked() && s2.isChecked() && s3.isChecked()) + b.setEnabled(true); + else + b.setEnabled(false); + + if (s.isChecked()) { + Handler h = new Handler(); + h.postDelayed(new Runnable() { + @Override + public void run() { + ImageButton b = findViewById(R.id.btnInfraPanic); + s.setChecked(false); + b.setEnabled(false); + } + }, 10000); + } + } + + + public void startSettingsActivity(@SuppressWarnings("unused") View view) { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + } + +} diff --git a/app/src/main/java/org/bandie/yipanic/PasscodeActivity.java b/app/src/main/java/org/bandie/yipanic/PasscodeActivity.java new file mode 100644 index 0000000..13c388c --- /dev/null +++ b/app/src/main/java/org/bandie/yipanic/PasscodeActivity.java @@ -0,0 +1,120 @@ +package org.bandie.yipanic; + +import android.content.Intent; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.EditText; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.security.crypto.EncryptedSharedPreferences; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Random; + +public class PasscodeActivity extends AppCompatActivity { + + private String passcode; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_passcode); + + try { + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + getApplicationContext(), + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + this.passcode = sharedPreferences.getString("passcode", null); + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + } + + if (this.passcode == null) { + Intent intent = new Intent(this, CommandActivity.class); + startActivity(intent); + } + } + + @Override + protected void onResume() { + super.onResume(); + try { + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + getApplicationContext(), + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + this.passcode = sharedPreferences.getString("passcode", null); + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yip", e.getMessage()); + else + Log.e("Yip", "[ No exception message ]"); + } + + if (this.passcode == null) { + Intent intent = new Intent(this, CommandActivity.class); + startActivity(intent); + } + } + + private void checkPasscode() { + EditText v = findViewById(R.id.pwPasscodeInput); + if (v.getText().toString().equals(this.passcode) || this.passcode == null) { + v.setText(""); + Intent intent = new Intent(this, CommandActivity.class); + startActivity(intent); + } else { + v.setText(""); + v.setError("Passcode wrong."); + } + } + + public void yip(@SuppressWarnings("unused") View view) { + int audio; + + switch (new Random().nextInt(4)) { + default: + case 0: + audio = R.raw.yip1; + break; + case 1: + audio = R.raw.yip2; + break; + case 2: + audio = R.raw.yip3; + break; + case 3: + audio = R.raw.yip4; + break; + } + + MediaPlayer mp = MediaPlayer.create(this, audio); + mp.start(); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_ENTER) { + this.checkPasscode(); + return true; + } + return true; + } + +} diff --git a/app/src/main/java/org/bandie/yipanic/SettingsActivity.java b/app/src/main/java/org/bandie/yipanic/SettingsActivity.java new file mode 100644 index 0000000..2bb1d0b --- /dev/null +++ b/app/src/main/java/org/bandie/yipanic/SettingsActivity.java @@ -0,0 +1,197 @@ +package org.bandie.yipanic; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.NavUtils; +import androidx.security.crypto.EncryptedSharedPreferences; + +import com.google.android.material.snackbar.Snackbar; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +public class SettingsActivity extends AppCompatActivity { + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case 16908332: + case R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + ActionBar actionBar = getSupportActionBar(); + EditText srv = findViewById(R.id.textServer); + + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + try { + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + getApplicationContext(), + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + String server = sharedPreferences.getString("server", null); + srv.setText(server); + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + } + + } + + @Override + protected void onPause() { + super.onPause(); + this.finish(); + } + + public void saveServerSettings(View view) { + Snackbar sbSaved = Snackbar.make(view, "Server settings saved! <3", 3000); + Snackbar sbFailedToSave = Snackbar.make(view, "Couldn't save settings! :'(", 3000); + try { + EditText srv = findViewById(R.id.textServer); + EditText k = findViewById(R.id.pwKey); + EditText s = findViewById(R.id.pwSecret); + + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + this, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + + SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); + sharedPrefsEditor.putString("server", srv.getText().toString()); + if (!k.getText().toString().equals("")) + sharedPrefsEditor.putString("key", k.getText().toString()); + if (!s.getText().toString().equals("")) + sharedPrefsEditor.putString("secret", s.getText().toString()); + + sharedPrefsEditor.apply(); + sbSaved.show(); + + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + sbFailedToSave.show(); + } + + } + + public void savePasscode(View view) { + Snackbar sbSaved = Snackbar.make(view, "Passcode saved! <3", 3000); + Snackbar sbFailedToSave = Snackbar.make(view, "Couldn't save! :'(", 3000); + try { + EditText pc = findViewById(R.id.pwSetPasscode); + EditText pcc = findViewById(R.id.pwSetPasscodeConfirm); + String pcS = pc.getText().toString(); + String pccS = pcc.getText().toString(); + + if (pcS.equals("") || pccS.equals("")) { + pc.setError("Passcode is empty. >;("); + pcc.setError("Passcode is empty. >;("); + sbFailedToSave.show(); + return; + } + + if (pcS.length() < 4) { + pc.setError("Passcode needs to have at least 4 digits."); + pcc.setError("Passcode needs to have at least 4 digits."); + sbFailedToSave.show(); + return; + } + + if (!pcS.equals(pccS)) { + pc.setError("Passcode didn't match. ;("); + pcc.setError("Passcode didn't match. ;("); + sbFailedToSave.show(); + return; + } + + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + this, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + + SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); + sharedPrefsEditor.putString("passcode", pcS); + sharedPrefsEditor.apply(); + sbSaved.show(); + pc.setText(""); + pcc.setText(""); + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + sbFailedToSave.show(); + } + } + + public void deletePasscode(View view) { + Snackbar sbSaved = Snackbar.make(view, "Passcode deleted! D:", 3000); + Snackbar sbFailedToSave = Snackbar.make(view, "Couldn't delete passcode! :'(", 3000); + try { + EditText pc = findViewById(R.id.pwSetPasscode); + String pcS = pc.getText().toString(); + + EncryptedSharedPreferences sharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences + .create( + "Yipanic", + "Yipanic", + this, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); + + SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); + + if (pcS.equals(sharedPreferences.getString("passcode", null))) { + sharedPrefsEditor.remove("passcode"); + sharedPrefsEditor.apply(); + sbSaved.show(); + } else { + pc.setError("Wrong passcode."); + sbFailedToSave.show(); + } + + } catch (IOException | GeneralSecurityException e) { + if (e.getMessage() != null) + Log.e("Yipanic", e.getMessage()); + else + Log.e("Yipanic", "[ No exception message ]"); + sbFailedToSave.show(); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bandie.png b/app/src/main/res/drawable/bandie.png new file mode 100644 index 0000000..360f399 Binary files /dev/null and b/app/src/main/res/drawable/bandie.png differ diff --git a/app/src/main/res/layout/activity_passcode.xml b/app/src/main/res/layout/activity_passcode.xml new file mode 100644 index 0000000..010a7b0 --- /dev/null +++ b/app/src/main/res/layout/activity_passcode.xml @@ -0,0 +1,43 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/command_activity.xml b/app/src/main/res/layout/command_activity.xml new file mode 100644 index 0000000..04cdd9e --- /dev/null +++ b/app/src/main/res/layout/command_activity.xml @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml new file mode 100644 index 0000000..027b341 --- /dev/null +++ b/app/src/main/res/layout/settings_activity.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + +