Move PWD sync to Home sync button + Fix VNC arg edit not saving in profile
Some checks are pending
Android CI / build (push) Waiting to run

This commit is contained in:
Jérémy Munsch 2023-08-11 17:40:30 +02:00
parent 708bba6f59
commit 478f6334ec
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
4 changed files with 112 additions and 124 deletions

View file

@ -8,11 +8,14 @@ import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.gaurav.avnc.R
import com.gaurav.avnc.model.ServerProfile
import com.gaurav.avnc.ui.ldc.lib.ApplicationInfo
import com.gaurav.avnc.ui.ldc.lib.exceptions.InvalidUriException
import com.gaurav.avnc.viewmodel.HomeViewModel
import java.net.InetAddress
import java.net.UnknownHostException
@ -111,7 +114,21 @@ class KioskParameterActivity : AppCompatActivity(), View.OnClickListener {
} catch(e: UnknownHostException) {
toastMessage(this, "L'adresse ip n'est pas valide")
}
toastMessage(this, "Enregistré")
Thread {
val viewModel by viewModels<HomeViewModel>()
var profile = appInfo.loadProfile(viewModel)
if (profile == null) {
profile = ServerProfile()
profile.host = appInfo.vncArgIp.hostAddress
profile.port = appInfo.vncArgPort
viewModel.insertProfile(profile)
} else {
profile.host = appInfo.vncArgIp.hostAddress
profile.port = appInfo.vncArgPort
viewModel.updateProfile(profile)
}
toastMessage(this, "Enregistré")
}.start()
}
/**

View file

@ -1,6 +1,5 @@
package com.gaurav.avnc.ui.ldc
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
@ -14,23 +13,9 @@ import android.widget.EditText
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.toColorInt
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.gaurav.avnc.R
import com.gaurav.avnc.ui.ldc.lib.ApplicationInfo
import com.github.fge.jsonschema.main.JsonSchema
import com.github.fge.jsonschema.main.JsonSchemaFactory
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.*
import java.io.IOException
import java.io.InputStream
class KioskParameterPasswordActivity : AppCompatActivity(), View.OnClickListener {
@ -81,7 +66,6 @@ class KioskParameterPasswordActivity : AppCompatActivity(), View.OnClickListener
// * AppInfo Refresh
appInfo.refreshConfigProperties()
appInfo.retrieveDeviceNetworkInfo(applicationContext)
//fetchConfigPassword(this)
}
// * Action UI events
@ -112,111 +96,6 @@ class KioskParameterPasswordActivity : AppCompatActivity(), View.OnClickListener
runOnUiThread {editTextPassword.setTextColor(Color.BLACK) }
startActivity(Intent(this, KioskParameterActivity::class.java))
}
/**
* Try to fetch config password from server
*/
private fun fetchConfigPassword(activity: KioskParameterPasswordActivity) {
val client = OkHttpClient()
val request = Request.Builder()
.url(activity.appInfo.appConfigUri.toString())
.build()
manageButtons(false)
val callback = object : Callback {
override fun onFailure(call: Call, e: IOException) {
toastMessage(activity, "Erreur : ${e.message} - ${e.cause?.message}")
manageButtons(true)
return
}
@SuppressLint("SetTextI18n")
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) {
toastMessage(activity ,"Erreur (${response.code}) : ${response.message}")
manageButtons(true)
return
}
val bodyResponse = response.body?.string()
if (bodyResponse == null) {
toastMessage(activity, "Erreur réponse vide du serveur")
manageButtons(true)
return
}
runOnUiThread {
if(!isJSONValid(bodyResponse)) {
toastMessage(activity, "Erreur réponse invalide du serveur")
manageButtons(true)
} else {
saveJSONPassword(bodyResponse)
manageButtons(true)
}
}
return
}
}
}
client.newCall(request).enqueue(callback)
}
/**
* Manage button to hold
*/
private fun manageButtons(enable: Boolean) {
runOnUiThread {
if (enable) {
btnSubmitPassword?.isEnabled = true
btnSubmitPassword?.isClickable = true
btnSubmitPassword?.setBackgroundColor("#D4021D".toColorInt())
} else {
btnSubmitPassword?.isEnabled = false
btnSubmitPassword?.isClickable = false
btnSubmitPassword?.setBackgroundColor(Color.GRAY)
}
}
}
/**
* Validate Json parameter schema
*/
private fun isJSONValid(jsonString: String): Boolean {
// * Validate JSON
try {
JSONObject(jsonString)
} catch (ex: JSONException) {
try {
JSONArray(jsonString)
} catch (ex1: JSONException) {
return false
}
}
// * Validate JSON Schema
return try {
val factory: JsonSchemaFactory = JsonSchemaFactory.byDefault()
val inputStream: InputStream = assets.open("security.schema.json");
val schemaString = inputStream.bufferedReader().use{it.readText()}
val m = ObjectMapper()
val jsonSchema: JsonSchema = factory.getJsonSchema(m.readTree(schemaString))
jsonSchema.validate(m.readTree(jsonString)).isSuccess
} catch(e: JsonProcessingException) {
false
}
}
/**
* Save Json password
*/
private fun saveJSONPassword(jsonString: String) {
val mapper = ObjectMapper()
val configNode = mapper.readValue<Map<String, String>>(jsonString, object : TypeReference<Map<String, String>>() {})
appInfo.setPassword(configNode["password"]!!)
}
/**
* Display toast message
*/

View file

@ -16,6 +16,9 @@ import androidx.core.graphics.toColorInt
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.gaurav.avnc.R
import com.gaurav.avnc.model.ServerProfile
import com.gaurav.avnc.ui.ldc.KioskActivity
@ -24,6 +27,8 @@ import com.gaurav.avnc.ui.ldc.events.AppSwitchedToForegroundEvent
import com.gaurav.avnc.ui.ldc.events.NetworkStateChangedEvent
import com.gaurav.avnc.ui.vnc.startVncActivity
import com.gaurav.avnc.viewmodel.HomeViewModel
import com.github.fge.jsonschema.main.JsonSchema
import com.github.fge.jsonschema.main.JsonSchemaFactory
import com.google.common.net.InetAddresses
import okhttp3.Call
import okhttp3.Callback
@ -36,8 +41,12 @@ import org.apache.commons.csv.CSVRecord
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.Reader
import java.net.InetAddress
import java.util.regex.Matcher
@ -175,6 +184,8 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
manageButtons(true)
// Download Config File
loadDistantConfiguration(fragment)
// Download Password config
fetchConfigPassword(fragment)
}
/**
@ -279,6 +290,87 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
client.newCall(request).enqueue(callback)
}
/**
* Try to fetch config password from server
*/
private fun fetchConfigPassword(fragment: KioskHomeFragment) {
val activity = (fragment.activity as KioskActivity)
val client = OkHttpClient()
val request = Request.Builder()
.url(activity.appInfo.appConfigUri.toString())
.build()
val callback = object : Callback {
override fun onFailure(call: Call, e: IOException) {
toastMessage(activity, "Erreur : ${e.message} - ${e.cause?.message}")
return
}
@SuppressLint("SetTextI18n")
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) {
toastMessage(activity ,"Erreur (${response.code}) : ${response.message}")
return
}
val bodyResponse = response.body?.string()
if (bodyResponse == null) {
toastMessage(activity, "Erreur réponse vide du serveur")
return
}
if(!isJSONValid(activity, bodyResponse)) {
toastMessage(activity, "Erreur réponse invalide du serveur")
} else {
saveJSONPassword(activity, bodyResponse)
}
return
}
}
}
client.newCall(request).enqueue(callback)
}
/**
* Validate Json parameter schema
*/
private fun isJSONValid(activity: KioskActivity, jsonString: String): Boolean {
// * Validate JSON
try {
JSONObject(jsonString)
} catch (ex: JSONException) {
try {
JSONArray(jsonString)
} catch (ex1: JSONException) {
return false
}
}
// * Validate JSON Schema
return try {
val factory: JsonSchemaFactory = JsonSchemaFactory.byDefault()
val inputStream: InputStream = activity.assets.open("security.schema.json");
val schemaString = inputStream.bufferedReader().use{it.readText()}
val m = ObjectMapper()
val jsonSchema: JsonSchema = factory.getJsonSchema(m.readTree(schemaString))
jsonSchema.validate(m.readTree(jsonString)).isSuccess
} catch(e: JsonProcessingException) {
false
}
}
/**
* Save Json password
*/
private fun saveJSONPassword(activity: KioskActivity, jsonString: String) {
val mapper = ObjectMapper()
val configNode = mapper.readValue<Map<String, String>>(jsonString, object : TypeReference<Map<String, String>>() {})
activity.appInfo.setPassword(configNode["password"]!!)
}
/**
* Display network info
*/

View file

@ -43,7 +43,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
/**
* Shared preferences items for dynamic update
*/
val sharedPreferencesFields = mapOf<String,Set<String>>(
private val sharedPreferencesFields = mapOf<String,Set<String>>(
"Int" to setOf<String>("vncArgPort"),
"InetAddress" to setOf<String>("vncArgIp"),
"String" to setOf<String>("configPassword", "configServerFqdn", "configServerPath", "appConfigPath"),
@ -87,7 +87,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
refreshConfigProperties()
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, s ->
sharedPreferencesFields.forEach(fun (key, items) {
if (items.indexOf(s) !== -1) {
if (items.indexOf(s) != -1) {
when (key) {
"Int" -> initProp(s, sharedPreferences.getString(s,
readInstanceProperty<Int>(this, s).toString()