diff --git a/.gitignore b/.gitignore index ea21e19..28e0dd4 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,10 @@ gastest.o #Private data private/ + +# Release APK +app/release/ + +# Proguard generated files +app/seeds.txt +app/usage.txt diff --git a/app/build.gradle b/app/build.gradle index 1f5a9f0..60fc6ef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ android { targetSdkVersion 33 versionCode 14 //versionName "2.2.3" - versionName "1.0.0" + versionName "1.0.1" javaCompileOptions { annotationProcessorOptions { @@ -82,10 +82,8 @@ android { } packagingOptions { - pickFirst 'META-INF/ASL-2.0.txt' - pickFirst 'META-INF/LGPL-3.0.txt' - pickFirst 'draftv4/schema' - pickFirst 'draftv3/schema' + exclude 'META-INF/ASL-2.0.txt' + exclude 'META-INF/LGPL-3.0.txt' } externalNativeBuild { @@ -125,19 +123,17 @@ dependencies { implementation files('libs/com.serialIntCaster-1.1.0.jar') // Life-cycle - implementation 'androidx.lifecycle:lifecycle-process:2.5.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" + implementation "androidx.lifecycle:lifecycle-process:2.4.0" + implementation "androidx.lifecycle:lifecycle-common:2.4.0" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0" // Json - implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8" - implementation "com.fasterxml.jackson.core:jackson-core:2.9.8" - implementation "com.fasterxml.jackson.core:jackson-annotations:2.9.8" - implementation "com.github.fge:jackson-coreutils:1.8" - implementation "com.github.fge:json-schema-core:1.2.5" - implementation "com.github.fge:json-schema-validator:2.2.6" + implementation "com.networknt:json-schema-validator:1.0.70" kapt "androidx.room:room-compiler:2.4.3" + implementation "com.google.guava:guava:30.0-android" + implementation "com.google.android.material:material:1.7.0" implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' diff --git a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskActivity.kt index 741f976..693ded6 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskActivity.kt @@ -54,7 +54,6 @@ class KioskActivity : AppCompatActivity(), LifecycleObserver { */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - ProcessLifecycleOwner.get().lifecycle.addObserver(this) setContentView(R.layout.activity_kiosk) // * Setup AppInfo @@ -97,6 +96,8 @@ class KioskActivity : AppCompatActivity(), LifecycleObserver { // Check NetWork Connection listenToNetworkConnectionChanges() + + ProcessLifecycleOwner.get().lifecycle.addObserver(this) } /** diff --git a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskDiagnosticActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskDiagnosticActivity.kt index 9999666..d83a947 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskDiagnosticActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskDiagnosticActivity.kt @@ -9,11 +9,14 @@ import android.content.DialogInterface import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager +import android.graphics.Color +import android.graphics.Typeface import android.location.LocationManager import android.net.wifi.WifiManager import android.os.Bundle import android.os.PowerManager import android.provider.Settings +import android.util.Log import android.view.LayoutInflater import android.view.View import android.widget.Button @@ -70,6 +73,9 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener { super.onCreate(savedInstanceState) setContentView(R.layout.activity_kiosk_diagnostic) + // * Setup AppInfo + appInfo = ApplicationInfo(PreferenceManager.getDefaultSharedPreferences(applicationContext)) + // * Request Permissions permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> isInternetPermissionGranted = permissions[Manifest.permission.INTERNET] ?: isInternetPermissionGranted @@ -94,8 +100,6 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener { btnRefresh.setOnClickListener(this) btnGoBack.setOnClickListener(this) - // * Setup AppInfo - appInfo = ApplicationInfo(PreferenceManager.getDefaultSharedPreferences(applicationContext)) // * Wont be able to => Hide btnReboot.visibility = View.INVISIBLE @@ -193,6 +197,14 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener { // * Scan changed resetWifiTableView() + val actualNetworkName = + if(mWifiManager.connectionInfo.ssid.length === 0) + mWifiManager.connectionInfo.bssid.replace('"', ' ').trim() + else mWifiManager.connectionInfo.ssid.replace('"', ' ').trim() + val actualNetworkFreq = getWifiType(mWifiManager.connectionInfo.frequency) + + Log.d("ACTUAL NETWORK", actualNetworkName) + mWifiManager.scanResults.forEach{ /** From -100 to 0 * https://stackoverflow.com/questions/15797920/how-to-convert-wifi-signal-strength-from-quality-percent-to-rssi-dbm/15798024#15798024 @@ -200,11 +212,19 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener { var precisePercent = if (it.level <= -100) 0 else if(it.level >= -50) 100 else 2 * (it.level + 100); val row = LayoutInflater.from(this@KioskDiagnosticActivity) .inflate(R.layout.activity_kiosk_diagnostic_wifi_row, null) as TableRow - val networkName = if(it.SSID.length === 0) it.BSSID else it.SSID + val networkName = if(it.SSID.length === 0) + it.BSSID.replace('"', ' ').trim() + else it.SSID.replace('"', ' ').trim() + Log.d("NETWORK", networkName) (row.findViewById(R.id.tableCellSSID) as TextView).text = networkName.substring(0, min(networkName.length, 18)) (row.findViewById(R.id.tableCellSignal) as TextView).text = it.level.toString() (row.findViewById(R.id.tableCellSignalPercent) as TextView).text = "$precisePercent %" (row.findViewById(R.id.tableCellSignalFreq) as TextView).text = getWifiType(it.frequency) + if (actualNetworkName == networkName && actualNetworkFreq == getWifiType(it.frequency)) { + val ssidTextView = (row.findViewById(R.id.tableCellSSID) as TextView) + ssidTextView.setTypeface(ssidTextView.typeface, Typeface.BOLD_ITALIC) + ssidTextView.setTextColor(Color.BLACK) + } tableLayoutWifiRows.addView(row) } diff --git a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskPingActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskPingActivity.kt index 9d19b9b..ed5c31b 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskPingActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/ldc/KioskPingActivity.kt @@ -137,7 +137,7 @@ class KioskPingActivity : AppCompatActivity(), View.OnClickListener { toastMessage(this, "FQDN AVG $avg ms") runOnUiThread { textResult.text = "Accessible ${inetToPing.hostAddress}" - textResult.setTextColor(Color.GREEN) + textResult.setTextColor("#009933".toColorInt()) } return@Thread } catch(e: PingFailedException) { diff --git a/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskHomeFragment.kt b/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskHomeFragment.kt index f1e802f..f8e8975 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskHomeFragment.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskHomeFragment.kt @@ -5,6 +5,7 @@ import android.app.Activity import android.content.Intent import android.graphics.Color import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -18,6 +19,7 @@ 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.JsonMappingException import com.fasterxml.jackson.databind.ObjectMapper import com.gaurav.avnc.R import com.gaurav.avnc.model.ServerProfile @@ -25,11 +27,13 @@ import com.gaurav.avnc.ui.ldc.KioskActivity import com.gaurav.avnc.ui.ldc.KioskParameterPasswordActivity import com.gaurav.avnc.ui.ldc.events.AppSwitchedToForegroundEvent import com.gaurav.avnc.ui.ldc.events.NetworkStateChangedEvent +import com.gaurav.avnc.ui.ldc.lib.exceptions.PasswordValidationException 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 com.networknt.schema.JsonSchemaFactory +import com.networknt.schema.SchemaValidatorsConfig +import com.networknt.schema.SpecVersion import okhttp3.Call import okhttp3.Callback import okhttp3.OkHttpClient @@ -88,9 +92,6 @@ class KioskHomeFragment : Fragment(), View.OnClickListener { */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - // * Register event bus - EventBus.getDefault().register(this) } /** @@ -126,6 +127,9 @@ class KioskHomeFragment : Fragment(), View.OnClickListener { btnVNC.setOnClickListener(this) btnParameters.setOnClickListener(this) + // * Register event bus + EventBus.getDefault().register(this) + return view; } @@ -321,8 +325,13 @@ class KioskHomeFragment : Fragment(), View.OnClickListener { if(!isJSONValid(activity, bodyResponse)) { toastMessage(activity, "Erreur réponse invalide du serveur") + return } else { - saveJSONPassword(activity, bodyResponse) + try { + saveJSONPassword(activity, bodyResponse) + } catch(e: PasswordValidationException) { + toastMessage(activity, "Erreur mot de passe sur le serveur est invalide") + } } return } @@ -348,21 +357,39 @@ class KioskHomeFragment : Fragment(), View.OnClickListener { // * 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 inputStream: InputStream = resources.assets.open("security.schema.json"); + val schemaString = inputStream.reader().readText() + val schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4) + val schema = schemaFactory.getSchema(schemaString) - val m = ObjectMapper() - val jsonSchema: JsonSchema = factory.getJsonSchema(m.readTree(schemaString)) + val config: SchemaValidatorsConfig = SchemaValidatorsConfig() + Log.d("test", config.toString()) - jsonSchema.validate(m.readTree(jsonString)).isSuccess + val jsonNode = ObjectMapper().readTree(jsonString) + + // * Validate json against schema + val errors = schema.validate(jsonNode) + + if (errors.size > 0) { + Log.d("JSON", "Invalid JSON against schema") + return false + } + + return true + } catch(e: IOException) { + false } catch(e: JsonProcessingException) { + Log.d("JSON", e.message) + false + } catch(e: JsonMappingException) { + Log.d("JSON", e.message) false } } /** * Save Json password + * @throws com.gaurav.avnc.ui.ldc.lib.exceptions.PasswordValidationException */ private fun saveJSONPassword(activity: KioskActivity, jsonString: String) { val mapper = ObjectMapper() diff --git a/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskInformationFragment.kt b/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskInformationFragment.kt index 85ee8a2..49847af 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskInformationFragment.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/ldc/fragments/KioskInformationFragment.kt @@ -5,8 +5,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.GridLayout +import android.widget.LinearLayout import android.widget.TextView import androidx.core.view.children import androidx.fragment.app.Fragment @@ -24,8 +23,7 @@ import org.greenrobot.eventbus.ThreadMode class KioskInformationFragment : Fragment(), View.OnClickListener { // * View Elements - private lateinit var infoGridLayout: GridLayout - private lateinit var btnReloadInfo: Button + private lateinit var infoLinearLayout: LinearLayout /** * On Start @@ -71,11 +69,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener { // Inflate the layout for this fragment val view:View = inflater.inflate(R.layout.fragment_kiosk_information, container, false) - infoGridLayout = view.findViewById(R.id.infoGridLayout) - btnReloadInfo = view.findViewById