From e19577b5ebd40c235f933ac54d61f1c6442cd71a Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Fri, 17 Aug 2018 00:25:22 +0200
Subject: Added secure oauth login and token storing

---
 .../main/java/com/no_name/no_name/LoginActivity.kt | 52 +++++++++---------
 .../main/java/com/no_name/no_name/MainActivity.kt  |  4 +-
 .../main/java/com/no_name/no_name/SecureStorage.kt | 61 ++++++++++++++++++++++
 3 files changed, 87 insertions(+), 30 deletions(-)
 create mode 100644 app/src/main/java/com/no_name/no_name/SecureStorage.kt

(limited to 'app/src/main/java/com')

diff --git a/app/src/main/java/com/no_name/no_name/LoginActivity.kt b/app/src/main/java/com/no_name/no_name/LoginActivity.kt
index 8cb61a3..154eb63 100644
--- a/app/src/main/java/com/no_name/no_name/LoginActivity.kt
+++ b/app/src/main/java/com/no_name/no_name/LoginActivity.kt
@@ -24,9 +24,10 @@ import android.view.inputmethod.EditorInfo
 import android.widget.ArrayAdapter
 import android.widget.TextView
 import android.widget.Toast
-import com.no_name.no_name.MainActivity
-import com.no_name.no_name.R
+import com.github.kittinunf.fuel.android.extension.responseJson
+import com.github.kittinunf.fuel.httpPost
 import kotlinx.android.synthetic.main.activity_login.*
+import org.json.JSONObject
 import java.util.*
 
 /**
@@ -243,23 +244,24 @@ class LoginActivity : AppCompatActivity(), LoaderCallbacks<Cursor> {
     inner class UserLoginTask internal constructor(private val mEmail: String, private val mPassword: String) : AsyncTask<Void, Void, Boolean>() {
 
         override fun doInBackground(vararg params: Void): Boolean? {
-            // TODO: attempt authentication against a network service.
-
-            try {
-                // Simulate network access.
-                Thread.sleep(1000)
-            } catch (e: InterruptedException) {
+            val credentialJson = JSONObject()
+            credentialJson.put("email", mEmail)
+            credentialJson.put("password", mPassword)
+
+            val (request, response, result) = "/login".httpPost()
+                    .header("Content-Type" to "application/json")
+                    .body(credentialJson.toString())
+                    .responseJson()
+
+            result.fold(success = {
+                val secureStorage = SecureStorage(this@LoginActivity)
+                val accessToken = result.get().obj().getString("access_token")
+                secureStorage.set("access_token", accessToken)
+                val verifyToken = secureStorage.get("access_token")
+                return verifyToken == accessToken
+            }, failure = {
                 return false
-            }
-
-            return DUMMY_CREDENTIALS
-                    .map { it.split(":") }
-                    .firstOrNull { it[0] == mEmail }
-                    ?.let {
-                        // Account exists, return true if the password matches.
-                        it[1] == mPassword
-                    }
-                    ?: true
+            })
         }
 
         override fun onPostExecute(success: Boolean?) {
@@ -267,13 +269,13 @@ class LoginActivity : AppCompatActivity(), LoaderCallbacks<Cursor> {
             showProgress(false)
 
             if (success!!) {
-                val toast = Toast.makeText(this@LoginActivity, "Successfully logged in.", Toast.LENGTH_LONG)
-                toast.setGravity(Gravity.CENTER, 0, 0)
-                toast.show()
-
                 val intent = Intent(this@LoginActivity, MainActivity::class.java)
                 //intent.putExtra("keyIdentifier", value)
                 startActivity(intent)
+
+                val toast = Toast.makeText(this@LoginActivity, "Successfully logged in.", Toast.LENGTH_LONG)
+                toast.setGravity(Gravity.CENTER, 0, 0)
+                toast.show()
             } else {
                 password.error = getString(R.string.error_incorrect_password)
                 password.requestFocus()
@@ -292,11 +294,5 @@ class LoginActivity : AppCompatActivity(), LoaderCallbacks<Cursor> {
          * Id to identity READ_CONTACTS permission request.
          */
         private val REQUEST_READ_CONTACTS = 0
-
-        /**
-         * A dummy authentication store containing known user names and passwords.
-         * TODO: remove after connecting to a real authentication system.
-         */
-        private val DUMMY_CREDENTIALS = arrayOf("foo@example.com:password")
     }
 }
diff --git a/app/src/main/java/com/no_name/no_name/MainActivity.kt b/app/src/main/java/com/no_name/no_name/MainActivity.kt
index 371ea97..10ae784 100644
--- a/app/src/main/java/com/no_name/no_name/MainActivity.kt
+++ b/app/src/main/java/com/no_name/no_name/MainActivity.kt
@@ -2,11 +2,10 @@ package com.no_name.no_name
 
 import android.content.Intent
 import android.os.Bundle
-import android.support.design.widget.Snackbar
 import android.support.v7.app.AppCompatActivity
 import android.view.Menu
 import android.view.MenuItem
-
+import com.github.kittinunf.fuel.core.FuelManager
 import kotlinx.android.synthetic.main.activity_main.*
 
 class MainActivity : AppCompatActivity() {
@@ -15,6 +14,7 @@ class MainActivity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
         setSupportActionBar(toolbar)
+        FuelManager.instance.basePath = "http://192.168.0.59"
 
         fab.setOnClickListener { view ->
             //Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
diff --git a/app/src/main/java/com/no_name/no_name/SecureStorage.kt b/app/src/main/java/com/no_name/no_name/SecureStorage.kt
new file mode 100644
index 0000000..5072f0d
--- /dev/null
+++ b/app/src/main/java/com/no_name/no_name/SecureStorage.kt
@@ -0,0 +1,61 @@
+package com.no_name.no_name
+
+import android.content.Context
+import android.preference.PreferenceManager
+import android.util.Base64
+import com.kazakago.cryptore.CipherAlgorithm
+import com.kazakago.cryptore.Cryptore
+import com.madapps.prefrences.EasyPrefrences
+
+
+class SecureStorage(private val context: Context) {
+    public fun set(key: String, value: String) {
+        sharedPrefs.putString(key, encryptAES(value))
+    }
+
+    public fun get(key: String): String {
+        return decryptAES(sharedPrefs.getString(key))
+    }
+
+    private val sharedPrefs = EasyPrefrences(context)
+
+    private enum class Alias(val value: String) {
+        RSA("CIPHER_RSA"),
+        AES("CIPHER_AES")
+    }
+
+    private val cryptoreAES: Cryptore by lazy {
+        val builder = Cryptore.Builder(alias = Alias.AES.value, type = CipherAlgorithm.AES)
+        // builder.blockMode = BlockMode.CBC //If Needed.
+        // builder.encryptionPadding = EncryptionPadding.PKCS7 //If Needed.
+        builder.build()
+    }
+
+    private fun encryptAES(plainStr: String): String {
+        val plainByte = plainStr.toByteArray()
+        val result = cryptoreAES.encrypt(plainByte = plainByte)
+        cipherIV = result.cipherIV
+        return Base64.encodeToString(result.bytes, Base64.DEFAULT)
+    }
+
+    private fun decryptAES(encryptedStr: String): String {
+        val encryptedByte = Base64.decode(encryptedStr, Base64.DEFAULT)
+        val result = cryptoreAES.decrypt(encryptedByte = encryptedByte, cipherIV = cipherIV)
+        return String(result.bytes)
+    }
+
+    private var cipherIV: ByteArray?
+        get() {
+            val preferences = PreferenceManager.getDefaultSharedPreferences(this.context)
+            preferences.getString("cipher_iv", null)?.let {
+                return Base64.decode(it, Base64.DEFAULT)
+            }
+            return null
+        }
+        set(value) {
+            val preferences = PreferenceManager.getDefaultSharedPreferences(this.context)
+            val editor = preferences.edit()
+            editor.putString("cipher_iv", Base64.encodeToString(value, Base64.DEFAULT))
+            editor.apply()
+        }
+}
\ No newline at end of file
-- 
cgit v1.2.3