Version 1.0.0 for release

Upgrade and fixes
- Fixes #2 change default pwd
- Fixes #5 change kios info display layout, removes refresh button
- Fixes #4 make ping status more visible
- Fixes #3 Make actual wifi network visible on wifi list
- Fix EventObserver LifeCycle on KioskActivity
- update git ignore
- Change Json schema validate lib + resolve fucking pro guard rules with it
- Fix password validation if password is too weak on server
This commit is contained in:
Jérémy Munsch 2023-09-05 14:40:51 +02:00
parent d5dfdbdaaa
commit 41c25ca049
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
11 changed files with 181 additions and 248 deletions

7
.gitignore vendored
View file

@ -39,3 +39,10 @@ gastest.o
#Private data
private/
# Release APK
app/release/
# Proguard generated files
app/seeds.txt
app/usage.txt

View file

@ -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'

View file

@ -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)
}
/**

View file

@ -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<View>(R.id.tableCellSSID) as TextView).text = networkName.substring(0, min(networkName.length, 18))
(row.findViewById<View>(R.id.tableCellSignal) as TextView).text = it.level.toString()
(row.findViewById<View>(R.id.tableCellSignalPercent) as TextView).text = "$precisePercent %"
(row.findViewById<View>(R.id.tableCellSignalFreq) as TextView).text = getWifiType(it.frequency)
if (actualNetworkName == networkName && actualNetworkFreq == getWifiType(it.frequency)) {
val ssidTextView = (row.findViewById<View>(R.id.tableCellSSID) as TextView)
ssidTextView.setTypeface(ssidTextView.typeface, Typeface.BOLD_ITALIC)
ssidTextView.setTextColor(Color.BLACK)
}
tableLayoutWifiRows.addView(row)
}

View file

@ -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) {

View file

@ -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()

View file

@ -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<GridLayout>(R.id.infoGridLayout)
btnReloadInfo = view.findViewById<Button>(R.id.btnReloadInfo)
btnReloadInfo.setOnClickListener(this)
btnReloadInfo.visibility = View.INVISIBLE
infoLinearLayout = view.findViewById<LinearLayout>(R.id.infoLinearLayout)
return view;
}
@ -95,9 +89,6 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
// * Action UI events
override fun onClick(v: View) {
Log.d("click", "click")
when (v.id) {
R.id.btnReloadInfo -> reloadNetWorkInfo(v, this)
}
}
/**
@ -123,7 +114,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
private fun displayTextInfo() {
// * Load actual network configuration
val activity = (activity as KioskActivity)
val cells = infoGridLayout.children as Sequence<TextView>
val cells = infoLinearLayout.children as Sequence<TextView>
val ip = activity.appInfo.ip
val gateway = activity.appInfo.gateway
@ -139,8 +130,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
)
info.onEachIndexed(fun (index, infoLine) {
(cells.elementAt(index * 2) as TextView).text = infoLine.key
(cells.elementAt(index * 2 + 1) as TextView).text = infoLine.value
(cells.elementAt(index ) as TextView).text = infoLine.key + "\t" + infoLine.value
})
}

View file

@ -68,7 +68,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
var vncArgPort: Int = 5900
private set
/** The default password for configuration */
var configPassword: String = "5XtpqEz!A5"
var configPassword: String = "73ezheJ8"
private set
/** The server FQDN from where config should be fetched */
private var configServerFqdn: String = "http://localtid"
@ -272,6 +272,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
/**
* Assign settings password
* @throws PasswordValidationException
*/
fun setPassword(password: String) {
// * Must contain lower, upper and number min 8 max 30

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#000"/>
<solid android:color="@android:color/transparent" />
</shape>
</inset>

View file

@ -68,7 +68,7 @@
android:text="Succès !"
android:textAlignment="center"
android:textColor="#000000"
android:textSize="15sp"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="parent" />

View file

@ -27,213 +27,93 @@
<LinearLayout
android:id="@+id/infoLinearLayout"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginTop="14dp"
android:layout_marginLeft="14dp"
android:layout_marginRight="14dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnReloadInfo">
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
<GridLayout
android:id="@+id/infoGridLayout"
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:columnCount="2"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
android:maxEms="15"
android:maxLines="4"
android:padding="10dp"
android:singleLine="false"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_top"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_rowWeight="1"
android:layout_columnSpan="1"
android:layout_columnWeight="1"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_top_no_left"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
</GridLayout>
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect_no_bottom"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="@drawable/bg_rect"
android:padding="10dp"
android:text="TEXT"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:lineHeight="18sp"/>
</LinearLayout>
<Button
android:id="@+id/btnReloadInfo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="24dp"
android:backgroundTint="#D4021D"
android:foreground="@drawable/ic_refresh"
android:foregroundTint="@color/design_default_color_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>