summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorMohamed Zenadi <mohamed@zenadi.com>2017-07-30 19:37:29 +0100
committerMohamed Zenadi <zeapo@users.noreply.github.com>2017-08-10 11:10:29 +0200
commitb145dfcf7f20c9d10cd5274e6582edb8a6e6b21c (patch)
tree5952f6ec043db3101b12d49a6b7444b905f2fda4 /app
parentd347e8349eae4520b4a27fe9239b0b7f25e54446 (diff)
Add Espresso for testing
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle26
-rw-r--r--app/src/androidTest/assets/store/dir1/f1.gpg0
-rw-r--r--app/src/androidTest/assets/store/dir1/f11.gpg0
-rw-r--r--app/src/androidTest/assets/store/dir2/f2.gpg0
-rw-r--r--app/src/androidTest/assets/store/dir3/dir4/f4.gpg0
-rw-r--r--app/src/androidTest/assets/store/dir3/f3.gpg0
-rw-r--r--app/src/androidTest/assets/store/name1.gpg0
-rw-r--r--app/src/androidTest/assets/store/name2.gpg0
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt97
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt171
10 files changed, 212 insertions, 82 deletions
diff --git a/app/build.gradle b/app/build.gradle
index bb8f0183..d168c7c6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,6 +12,8 @@ android {
targetSdkVersion 25
versionCode 88
versionName "1.2.0.68"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
@@ -55,21 +57,35 @@ android {
}
dependencies {
- compile 'com.android.support:appcompat-v7:25.3.1'
- compile 'com.android.support:recyclerview-v7:25.3.1'
- compile 'com.android.support:cardview-v7:25.3.1'
- compile 'com.android.support:design:25.3.1'
+ compile 'com.android.support:appcompat-v7:25.4.0'
+ compile 'com.android.support:recyclerview-v7:25.4.0'
+ compile 'com.android.support:cardview-v7:25.4.0'
+ compile 'com.android.support:design:25.4.0'
+ compile 'com.android.support:support-annotations:25.4.0'
compile 'org.sufficientlysecure:openpgp-api:11.0'
compile 'com.nononsenseapps:filepicker:2.4.2'
compile('org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r') {
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
- compile 'com.jcraft:jsch:0.1.53'
+ compile 'com.jcraft:jsch:0.1.54'
compile 'org.apache.commons:commons-io:1.3.2'
compile 'com.jayway.android.robotium:robotium-solo:5.3.1'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.android.support.constraint:constraint-layout:1.0.2'
+
+ // Testing-only dependencies
+ androidTestCompile 'junit:junit:4.12'
+ androidTestCompile 'org.mockito:mockito-core:2.8.47'
+ androidTestCompile 'com.android.support.test:runner:1.0.0'
+ androidTestCompile 'com.android.support.test:rules:1.0.0'
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.0'
+ androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.0'
+
+
}
repositories {
mavenCentral()
+
+ // temp. solution until we use use gradle 4.0
+ maven { url 'https://maven.google.com' }
}
diff --git a/app/src/androidTest/assets/store/dir1/f1.gpg b/app/src/androidTest/assets/store/dir1/f1.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/dir1/f1.gpg
diff --git a/app/src/androidTest/assets/store/dir1/f11.gpg b/app/src/androidTest/assets/store/dir1/f11.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/dir1/f11.gpg
diff --git a/app/src/androidTest/assets/store/dir2/f2.gpg b/app/src/androidTest/assets/store/dir2/f2.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/dir2/f2.gpg
diff --git a/app/src/androidTest/assets/store/dir3/dir4/f4.gpg b/app/src/androidTest/assets/store/dir3/dir4/f4.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/dir3/dir4/f4.gpg
diff --git a/app/src/androidTest/assets/store/dir3/f3.gpg b/app/src/androidTest/assets/store/dir3/f3.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/dir3/f3.gpg
diff --git a/app/src/androidTest/assets/store/name1.gpg b/app/src/androidTest/assets/store/name1.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/name1.gpg
diff --git a/app/src/androidTest/assets/store/name2.gpg b/app/src/androidTest/assets/store/name2.gpg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/androidTest/assets/store/name2.gpg
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt
new file mode 100644
index 00000000..52e1e65d
--- /dev/null
+++ b/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt
@@ -0,0 +1,97 @@
+package com.zeapo.pwdstore
+
+import android.content.Context
+import android.content.Intent
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.util.Log
+import com.zeapo.pwdstore.crypto.PgpActivity
+import kotlinx.android.synthetic.main.decrypt_layout.*
+import org.apache.commons.io.IOUtils
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class WelcomeActivityTest {
+ @Rule @JvmField
+ var mActivityRule: ActivityTestRule<PgpActivity> = ActivityTestRule(PgpActivity::class.java, true, false)
+
+ @Test
+ fun pathShouldDecompose() {
+ val path = "/data/my.app.com/files/store/cat1/name.gpg"
+ val repoPath = "/data/my.app.com/files/store"
+ assertEquals("/cat1/name.gpg", PgpActivity.getRelativePath(path, repoPath))
+ assertEquals("/cat1/", PgpActivity.getParentPath(path, repoPath))
+ assertEquals("name", PgpActivity.getName(path, repoPath))
+ assertEquals("name", PgpActivity.getName(path, "$repoPath/"))
+ }
+
+ @Test
+ fun activityShouldShowName() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val name = "name"
+ val parentPath = "/cat1/"
+ val repoPath = "${context.filesDir}/store/"
+ val path = "$repoPath/cat1/name.gpg"
+
+
+ val intent = Intent(context, PgpActivity::class.java)
+ intent.putExtra("OPERATION", "DECRYPT")
+ intent.putExtra("FILE_PATH", path)
+ intent.putExtra("REPO_PATH", repoPath)
+
+ copyAssets(context, "store", context.filesDir.absolutePath)
+
+ val activity: PgpActivity = mActivityRule.launchActivity(intent)
+
+ val categoryView = activity.crypto_password_category_decrypt
+ assertNotNull(categoryView)
+ assertEquals(parentPath, categoryView.text)
+
+ val nameView = activity.crypto_password_file
+ assertNotNull(nameView)
+ assertEquals(name, nameView.text)
+ }
+
+ companion object {
+ fun copyAssets(context: Context, source: String, destination: String) {
+ val assetManager = context.assets
+ val files: Array<String>? = assetManager.list(source)
+
+ files?.map { filename ->
+ val destPath = "$destination/$filename"
+ val sourcePath = "$source/$filename"
+ if (assetManager.list(filename).isNotEmpty()) {
+ File(destPath).mkdir()
+ copyAssets(context, "$source/$filename", destPath)
+ } else {
+ try {
+ val input = assetManager.open(sourcePath)
+ val outFile = File(destination, filename)
+ val output = FileOutputStream(outFile)
+ IOUtils.copy(input, output)
+ input.close()
+ output.flush()
+ output.close()
+ } catch (e: IOException) {
+ Log.e("tag", "Failed to copy asset file: " + filename, e)
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
index e48b9a03..96cca034 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
@@ -37,24 +37,17 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
}
var passwordEntry: PasswordEntry? = null
+ var api : OpenPgpApi? = null
- val name: String by lazy { intent.getStringExtra("NAME") }
+ val operation: String by lazy { intent.getStringExtra("OPERATION") }
val repoPath: String by lazy { intent.getStringExtra("REPO_PATH") }
+
val path: String by lazy { intent.getStringExtra("FILE_PATH") }
- val parentPath: String by lazy {
- // when encrypting we pass "PARENT_PATH" as we do not have a file
- if (operation == "ENCRYPT") intent.getStringExtra("PARENT_PATH")
- else File(path).parentFile.absolutePath
- }
- val cat: String by lazy { parentPath.replace(repoPath, "") }
- val operation: String by lazy { intent.getStringExtra("OPERATION") }
+ val name: String by lazy { getName(path, repoPath) }
+ val relativeParentPath: String by lazy { getParentPath(path, repoPath) }
- val settings: SharedPreferences by lazy {
- PreferenceManager.getDefaultSharedPreferences(this)
- }
- val keyIDs: MutableSet<String> by lazy {
- settings.getStringSet("openpgp_key_ids_set", emptySet())
- }
+ val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
+ val keyIDs: MutableSet<String> by lazy { settings.getStringSet("openpgp_key_ids_set", emptySet()) }
var mServiceConnection: OpenPgpServiceConnection? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -78,13 +71,13 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
when (operation) {
"DECRYPT", "EDIT" -> {
setContentView(R.layout.decrypt_layout)
- crypto_password_category_decrypt.text = "$cat/"
+ crypto_password_category_decrypt.text = relativeParentPath
crypto_password_file.text = name
}
"ENCRYPT" -> {
setContentView(R.layout.encrypt_layout)
title = getString(R.string.new_password_title)
- crypto_password_category.text = "$cat/"
+ crypto_password_category.text = relativeParentPath
}
}
}
@@ -178,6 +171,10 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
Log.e(TAG, "onError getMessage:" + error.message)
}
+ fun initOpenPgpApi() {
+ api = api ?: OpenPgpApi(this, mServiceConnection?.service)
+ }
+
private fun decryptAndVerify(receivedIntent: Intent? = null): Unit {
val data = receivedIntent ?: Intent()
data.action = ACTION_DECRYPT_VERIFY
@@ -185,64 +182,62 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val iStream = FileUtils.openInputStream(File(path))
val oStream = ByteArrayOutputStream()
- val api = OpenPgpApi(this, mServiceConnection?.service)
-
- api.executeApiAsync(data, iStream, oStream, { result: Intent? ->
+ api?.executeApiAsync(data, iStream, oStream, { result: Intent? ->
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
RESULT_CODE_SUCCESS -> {
try {
- val showPassword = settings.getBoolean("show_password", true)
- val showExtraContent = settings.getBoolean("show_extra_content", true)
-
- crypto_container_decrypt.visibility = View.VISIBLE
-
- val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
- val entry = PasswordEntry(oStream)
-
- passwordEntry = entry
-
- if (operation == "EDIT") {
- editPassword()
- return@executeApiAsync
- }
-
- crypto_password_show.typeface = monoTypeface
- crypto_password_show.text = entry.password
-
- crypto_password_toggle_show.visibility = if (showPassword) View.GONE else View.VISIBLE
- crypto_password_show.transformationMethod = if (showPassword) {
- null
- } else {
- HoldToShowPasswordTransformation(
- crypto_password_toggle_show,
- Runnable { crypto_password_show.text = entry.password }
- )
- }
-
- if (entry.hasExtraContent()) {
- crypto_extra_show_layout.visibility = if (showExtraContent) View.VISIBLE else View.GONE
-
- crypto_extra_show.typeface = monoTypeface
- crypto_extra_show.text = entry.extraContent
-
- if (entry.hasUsername()) {
- crypto_username_show.visibility = View.VISIBLE
- crypto_username_show_label.visibility = View.VISIBLE
- crypto_copy_username.visibility = View.VISIBLE
-
- crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username) }
- crypto_username_show.typeface = monoTypeface
- crypto_username_show.text = entry.username
- } else {
- crypto_username_show.visibility = View.GONE
- crypto_username_show_label.visibility = View.GONE
- crypto_copy_username.visibility = View.GONE
- }
- }
-
- if (settings.getBoolean("copy_on_decrypt", true)) {
- copyPasswordToClipBoard()
- }
+// val showPassword = settings.getBoolean("show_password", true)
+// val showExtraContent = settings.getBoolean("show_extra_content", true)
+//
+// crypto_container_decrypt.visibility = View.VISIBLE
+//
+// val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
+// val entry = PasswordEntry(oStream)
+//
+// passwordEntry = entry
+//
+// if (operation == "EDIT") {
+// editPassword()
+// return@executeApiAsync
+// }
+//
+// crypto_password_show.typeface = monoTypeface
+// crypto_password_show.text = entry.password
+//
+// crypto_password_toggle_show.visibility = if (showPassword) View.GONE else View.VISIBLE
+// crypto_password_show.transformationMethod = if (showPassword) {
+// null
+// } else {
+// HoldToShowPasswordTransformation(
+// crypto_password_toggle_show,
+// Runnable { crypto_password_show.text = entry.password }
+// )
+// }
+//
+// if (entry.hasExtraContent()) {
+// crypto_extra_show_layout.visibility = if (showExtraContent) View.VISIBLE else View.GONE
+//
+// crypto_extra_show.typeface = monoTypeface
+// crypto_extra_show.text = entry.extraContent
+//
+// if (entry.hasUsername()) {
+// crypto_username_show.visibility = View.VISIBLE
+// crypto_username_show_label.visibility = View.VISIBLE
+// crypto_copy_username.visibility = View.VISIBLE
+//
+// crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username) }
+// crypto_username_show.typeface = monoTypeface
+// crypto_username_show.text = entry.username
+// } else {
+// crypto_username_show.visibility = View.GONE
+// crypto_username_show_label.visibility = View.GONE
+// crypto_copy_username.visibility = View.GONE
+// }
+// }
+//
+// if (settings.getBoolean("copy_on_decrypt", true)) {
+// copyPasswordToClipBoard()
+// }
} catch (e: Exception) {
Log.e(TAG, "An Exception occurred", e)
}
@@ -284,10 +279,9 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val iStream = ByteArrayInputStream("$pass\n$extra".toByteArray(Charset.forName("UTF-8")))
val oStream = ByteArrayOutputStream()
- val api = OpenPgpApi(this, mServiceConnection?.service)
- val path = "$parentPath/$name.gpg"
+ val path = "$repoPath/$relativeParentPath/$name.gpg"
- api.executeApiAsync(data, iStream, oStream, { result: Intent? ->
+ api?.executeApiAsync(data, iStream, oStream, { result: Intent? ->
when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
OpenPgpApi.RESULT_CODE_SUCCESS -> {
try {
@@ -332,7 +326,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
crypto_extra_edit.setText(passwordEntry?.extraContent)
crypto_extra_edit.typeface = monoTypeface
- crypto_password_category.text = "$cat/"
+ crypto_password_category.text = relativeParentPath
crypto_password_file_edit.setText(name)
crypto_password_file_edit.isEnabled = false
@@ -351,8 +345,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
fun getKeyIds(receivedIntent: Intent? = null) {
val data = receivedIntent ?: Intent()
data.action = OpenPgpApi.ACTION_GET_KEY_IDS
- val api = OpenPgpApi(this, mServiceConnection?.service)
- api.executeApiAsync(data, null, null, { result: Intent? ->
+ api?.executeApiAsync(data, null, null, { result: Intent? ->
when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
OpenPgpApi.RESULT_CODE_SUCCESS -> {
try {
@@ -382,6 +375,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
* The action to take when the PGP service is bound
*/
override fun onBound(service: IOpenPgpService2?) {
+ initOpenPgpApi()
when (operation) {
"EDIT", "DECRYPT" -> decryptAndVerify()
"GET_KEY_ID" -> getKeyIds()
@@ -572,6 +566,29 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
private var delayTask: DelayShow? = null
+ /**
+ * Gets the relative path to the repository
+ */
+ fun getRelativePath(fullPath: String, repositoryPath: String): String =
+ fullPath.replace(repositoryPath, "").replace("//", "/")
+
+ /**
+ * Gets the Parent path, relative to the repository
+ */
+ fun getParentPath(fullPath: String, repositoryPath: String) : String {
+ val relativePath = getRelativePath(fullPath, repositoryPath)
+ val index = relativePath.lastIndexOf("/")
+ return "/${relativePath.substring(startIndex = 0, endIndex = index + 1)}/".replace("//", "/")
+ }
+
+ /**
+ * Gets the name of the password (excluding .gpg)
+ */
+ fun getName(fullPath: String, repositoryPath: String) : String {
+ val relativePath = getRelativePath(fullPath, repositoryPath)
+ val index = relativePath.lastIndexOf("/")
+ return relativePath.substring(index + 1).replace("\\.gpg$".toRegex(), "")
+ }
}
}