Skip to content

Commit

Permalink
[ADD] option for self-signed cert in configs.xml
Browse files Browse the repository at this point in the history
[IMP] added network log along with odoo debug trace in Prompt Report dialog
[IMP] other minor improvements
  • Loading branch information
Kasim Rangwala committed Feb 24, 2019
1 parent c9a1dc4 commit 1aa9967
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 33 deletions.
Binary file modified .idea/caches/build_file_checksums.ser
Binary file not shown.
Binary file removed Odoo.JsonRpc.Client.1.04.apk
Binary file not shown.
Binary file added Odoo.JsonRpc.Client.1.041.apk
Binary file not shown.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ android {
applicationId "io.gripxtech.odoojsonrpcclient"
minSdkVersion 17
targetSdkVersion 28
versionCode 5
versionName "1.04"
versionCode 6
versionName "1.041"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true

Expand Down
72 changes: 56 additions & 16 deletions app/src/main/java/io/gripxtech/odoojsonrpcclient/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,24 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.TaskStackBuilder
import androidx.core.content.FileProvider
import com.google.gson.*
import io.gripxtech.odoojsonrpcclient.core.Odoo
import io.gripxtech.odoojsonrpcclient.core.OdooUser
import io.gripxtech.odoojsonrpcclient.core.authenticator.SplashActivity
import io.gripxtech.odoojsonrpcclient.core.entities.Many2One
import io.gripxtech.odoojsonrpcclient.core.entities.odooError.OdooError
import io.gripxtech.odoojsonrpcclient.core.entities.session.authenticate.AuthenticateResult
import io.gripxtech.odoojsonrpcclient.core.utils.Retrofit2Helper
import io.gripxtech.odoojsonrpcclient.core.utils.android.ktx.subscribeEx
import io.gripxtech.odoojsonrpcclient.core.utils.decryptAES
import io.gripxtech.odoojsonrpcclient.core.utils.encryptAES
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.Response
import java.io.ByteArrayOutputStream
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

Expand Down Expand Up @@ -255,22 +262,55 @@ fun AppCompatActivity.promptReport(odooError: OdooError) {
showNeutralButton = true,
neutralButton = getString(R.string.error_report),
neutralButtonListener = DialogInterface.OnClickListener { _, _ ->
val intent = emailIntent(
address = arrayOf(getString(R.string.preference_contact_summary)),
cc = arrayOf(),
subject = "${getString(R.string.app_name)} ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) " +
getString(R.string.report_feedback),
body = "Name: ${odooError.data.name}\n\n" +
"Message: ${odooError.data.message}\n\n" +
"Exception Type: ${odooError.data.exceptionType}\n\n" +
"Arguments: ${odooError.data.arguments}\n\n" +
"Debug: ${odooError.data.debug}\n\n"
)
try {
startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
showMessage(message = getString(R.string.preference_error_email_intent))
val debugTraceFile = "debug-trace.txt"
Completable.fromCallable {
openFileOutput(debugTraceFile, Context.MODE_PRIVATE)?.use {
it.write(
("Name: ${odooError.data.name}\n\n" +
"Message: ${odooError.data.message}\n\n" +
"Exception Type: ${odooError.data.exceptionType}\n\n" +
"Arguments: ${odooError.data.arguments}\n\n" +
"Debug: ${odooError.data.debug}\n\n").toByteArray(charset = Charsets.UTF_8)
)
}
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeEx {
onSubscribe { }

onError {
it.printStackTrace()
}

onComplete {
val logFileUri = Retrofit2Helper.getLogfile()
val debugTraceUri = FileProvider.getUriForFile(
this@promptReport,
"$packageName.fileprovider",
File("$filesDir${File.pathSeparator}$debugTraceFile")
)
startActivity(
Intent.createChooser(
Intent(Intent.ACTION_SEND_MULTIPLE).apply {
type = "text/plain"
putExtra(Intent.EXTRA_EMAIL, arrayOf(getString(R.string.preference_contact_summary)))
putExtra(
Intent.EXTRA_SUBJECT,
"${getString(R.string.app_name)} ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) " +
getString(R.string.report_feedback)
)
putExtra(
Intent.EXTRA_TEXT,
"Name: ${odooError.data.name}\n\n" +
"Message: ${odooError.data.message}\n\n" +
"Exception Type: ${odooError.data.exceptionType}\n\n" +
"Arguments: ${odooError.data.arguments}\n\n"
)
putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayListOf(debugTraceUri, logFileUri))
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}, getString(R.string.preference_logfile_title)
)
)
}
}
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.gripxtech.odoojsonrpcclient.core.preferences

import android.content.ClipData
import android.content.Intent
import android.net.MailTo
import android.net.Uri
Expand All @@ -12,10 +13,12 @@ import com.google.android.material.snackbar.Snackbar
import io.gripxtech.odoojsonrpcclient.*
import io.gripxtech.odoojsonrpcclient.core.authenticator.SplashActivity
import io.gripxtech.odoojsonrpcclient.core.utils.LocalePrefs
import io.gripxtech.odoojsonrpcclient.core.utils.Retrofit2Helper
import io.gripxtech.odoojsonrpcclient.core.utils.android.ktx.subscribeEx
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import timber.log.Timber

class SettingsFragment : PreferenceFragmentCompat() {

Expand All @@ -27,6 +30,7 @@ class SettingsFragment : PreferenceFragmentCompat() {

private lateinit var build: Preference
private lateinit var language: ListPreference
private lateinit var logfile: Preference
private lateinit var organization: Preference
private lateinit var privacy: Preference
private lateinit var contact: Preference
Expand All @@ -38,6 +42,7 @@ class SettingsFragment : PreferenceFragmentCompat() {

build = findPreference(getString(R.string.preference_build_key))
language = findPreference(getString(R.string.preference_language_key)) as ListPreference
logfile = findPreference(getString(R.string.preference_logfile_key))
organization = findPreference(getString(R.string.preference_organization_key))
privacy = findPreference(getString(R.string.preference_privacy_policy_key))
contact = findPreference(getString(R.string.preference_contact_key))
Expand All @@ -63,6 +68,29 @@ class SettingsFragment : PreferenceFragmentCompat() {
true
}

logfile.setOnPreferenceClickListener {
val logFileUri = Retrofit2Helper.getLogfile()
activity.startActivity(
Intent.createChooser(
Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_EMAIL, arrayOf(getString(R.string.preference_contact_summary)))
putExtra(
Intent.EXTRA_SUBJECT,
"Contact by ${getString(R.string.app_name)} user: ${activity.getActiveOdooUser()?.name
?: "N/A"}"
)
putExtra(Intent.EXTRA_TEXT, "${getString(R.string.preference_logfile)}\n")
putExtra(Intent.EXTRA_STREAM, logFileUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
clipData = ClipData.newRawUri(Retrofit2Helper.networkLogFile, logFileUri)
}, getString(R.string.preference_logfile_title)
)
)
true
}

organization.setOnPreferenceClickListener {
startActivity(
Intent(
Expand All @@ -86,12 +114,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
contact.setOnPreferenceClickListener {
val lclContext = context
val url = ("mailto:" + getString(R.string.preference_contact_summary)
+ "?subject=Contact by " + getString(R.string.app_name) + " user " +
if (lclContext != null && lclContext.getActiveOdooUser() != null) {
lclContext.getActiveOdooUser()!!.name
} else {
"N/A"
})
+ "?subject=Contact by " + getString(R.string.app_name) + " user "
+ (lclContext?.getActiveOdooUser()?.name ?: "N/A"))
try {
val mt = MailTo.parse(url)
val i = emailIntent(arrayOf(mt.to), arrayOf(), mt.subject, "")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package io.gripxtech.odoojsonrpcclient.core.utils

import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import io.gripxtech.odoojsonrpcclient.App
import io.gripxtech.odoojsonrpcclient.R
import io.gripxtech.odoojsonrpcclient.core.Odoo
import io.gripxtech.odoojsonrpcclient.core.utils.android.ktx.subscribeEx
import io.gripxtech.odoojsonrpcclient.gson
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import timber.log.Timber
import java.io.File
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.*
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
Expand All @@ -23,6 +32,14 @@ class Retrofit2Helper(
) {
companion object {
const val TAG = "Retrofit2Helper"
const val networkLogFile = "network_log_file.txt"

fun getLogfile(): Uri {
val file = File("${app.filesDir}${File.pathSeparator}$networkLogFile")
return FileProvider.getUriForFile(
app, "${app.packageName}.fileprovider", file
)
}

enum class Protocol {
HTTP, HTTPS
Expand Down Expand Up @@ -82,34 +99,40 @@ class Retrofit2Helper(
private var cookies: MutableList<Cookie>? = Retrofit2Helper.app.cookiePrefs.getCookies()

override fun saveFromResponse(url: HttpUrl?, cookies: MutableList<Cookie>?) {
if (url.toString().contains("/web/session/authenticate") || url.toString().contains("web/session/check")) {
if (cookies != null && cookies.isNotEmpty()) {
this.cookies = cookies
if (cookies != null) {
Odoo.pendingAuthenticateCookies.clear()
Odoo.pendingAuthenticateCookies.addAll(cookies)
}
Odoo.pendingAuthenticateCookies.clear()
Odoo.pendingAuthenticateCookies.addAll(cookies)
}
}

override fun loadForRequest(url: HttpUrl?): MutableList<Cookie>? =
cookies
})
.addInterceptor { chain: Interceptor.Chain? ->
writeFile(dateStamp, Context.MODE_PRIVATE)
val original = chain!!.request()

val request = original.newBuilder()
.header("User-Agent", android.os.Build.MODEL)
.method(original.method(), original.body())
.build()

chain.proceed(request)
chain.proceed(request).also {
writeFile(dateStamp, Context.MODE_APPEND)
}
}
.addInterceptor(HttpLoggingInterceptor {
Timber.tag("OkHttp").d(it)
writeFile("$it\n", Context.MODE_APPEND)
}.apply {
level = HttpLoggingInterceptor.Level.BODY
})
/*.apply(::unsafeCert)*/
.apply {
if (app.resources.getBoolean(R.bool.self_signed_cert)) {
unsafeCert(this)
}
}
.build()

private fun unsafeCert(builder: OkHttpClient.Builder) {
Expand All @@ -129,4 +152,49 @@ class Retrofit2Helper(
builder.sslSocketFactory(sslSocketFactory, trustManagers[0] as X509TrustManager)
builder.hostnameVerifier { _, _ -> true }
}

private val dateStamp: String
get() = "------------------------- ${Date()}: -------------------------\n"

private var logOperationRunning = false
private var logOperationParams = ArrayList<Pair<String, Int>>()

private fun writeFile(fileContents: String, mode: Int, skipCheck: Boolean = false) {
if (skipCheck || !logOperationRunning) {
logOperationRunning = true
Completable.fromCallable {
app.openFileOutput(networkLogFile, mode)?.use {
if (fileContents.startsWith("Set-Cookie:")) {
it.write(fileContents.encryptAES().toByteArray(charset = Charsets.UTF_8))
} else {
it.write(fileContents.toByteArray(charset = Charsets.UTF_8))
}
}
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeEx {

fun popFirstParams() {
if (logOperationParams.isNotEmpty()) {
logOperationParams.removeAt(0).let {
writeFile(it.first, it.second, true)
}
} else {
logOperationRunning = false
}
}

onSubscribe { }

onError {
it.printStackTrace()
popFirstParams()
}

onComplete {
popFirstParams()
}
}
} else {
logOperationParams.add(Pair(fileContents, mode))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class MaybeObserverEx<T> : MaybeObserver<T> {
}

private var success: ((response: T) -> Unit) = {
Timber.d("onNext() called: response is $it")
Timber.d("onSuccess() called: response is $it")
}

fun onSuccess(success: (response: T) -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SingleObserverEx<T> : SingleObserver<T> {
}

private var success: ((response: T) -> Unit) = {
Timber.d("onNext() called: response is $it")
Timber.d("onSuccess() called: response is $it")
}

fun onSuccess(success: (response: T) -> Unit) {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
<string name="preference_build_summary">الإصدار %s</string>
<string name="preference_language_title">لغة</string>
<string name="preference_language_summary">اختر لغتك</string>
<string name="preference_logfile_title">مشاركة Logfile التطبيق</string>
<string name="preference_logfile">تطبيق logfile</string>
<string name="preference_about_category">حول</string>
<string name="preference_organization_title">طورت بواسطة</string>
<string name="preference_privacy_policy_title">سياسة خاصة</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
<string name="preference_build_summary">Versión %s</string>
<string name="preference_language_title">Idioma</string>
<string name="preference_language_summary">Elige tu idioma</string>
<string name="preference_logfile_title">Compartir la aplicación de archivo de registro</string>
<string name="preference_logfile">Aplicación de archivo de registro</string>
<string name="preference_about_category">Acerca de</string>
<string name="preference_organization_title">Desarrollado por</string>
<string name="preference_privacy_policy_title">Política de privacidad</string>
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/values/configs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<!-- set your database -->
<string name="pre_config_database_name" translatable="false">db_v11</string>

<!-- if your server is using self signed certificate for using HTTPS protocol then set self_signed_cert to true -->
<bool name="self_signed_cert">false</bool>

<!-- Compatible Odoo versions -->
<!-- Any other Odoo versions which are not in the array are considered as incompatible versions. -->
<string-array name="supported_odoo_versions">
Expand All @@ -39,6 +42,12 @@
<!-- organization email -->
<string name="preference_contact_summary" translatable="false">[email protected]</string>

<!-- To add a new language: -->
<!-- 1) Add language name & language code below -->
<!-- 2) Reference language name to the languages array -->
<!-- 3) Reference language code to the languages_codes array -->
<!-- 4) Add strings.xml for that language -->

<!-- language -->
<string name="language_spanish" translatable="false">Español (experimental)</string>
<string name="language_code_spanish" translatable="false">es</string>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
<string name="preference_language_key" translatable="false">language</string>
<string name="preference_language_title">Language</string>
<string name="preference_language_summary">Select Your Language</string>
<string name="preference_logfile_key" translatable="false">logfile</string>
<string name="preference_logfile_title">Share Application Logfile</string>
<string name="preference_logfile">Application Logfile</string>
<string name="preference_about_category">About</string>
<string name="preference_organization_key" translatable="false">organization</string>
<string name="preference_organization_title">Developed By</string>
Expand Down
Loading

0 comments on commit 1aa9967

Please sign in to comment.