feat(android): Cockpit-App und Android-Agent per MDM ausrollen
Beide Apps lesen ihre Verbindungsdaten aus der App-Konfiguration des MDM (Android Managed Configuration). Sind host und token gesetzt, verbindet sich die App ohne QR-Code; die MDM-Werte haben Vorrang vor der Eingabe am Geraet. - Cockpit (com.ariacockpit): host, token, port, tls; natives Modul MdmConfig, gelesen beim Start in rvs.loadConfig() - Agent (de.hackersoft.ariaagent): zusaetzlich name, control, reply_mode; gelesen beim App-Start und nach dem Booten - README: Abschnitt "Ausrollen per MDM" mit Screenshots unter docs/images/mdm/ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,10 @@
|
||||
android:allowBackup="false"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:theme="@style/AppTheme">
|
||||
<!-- MDM-Ausrollen: welche Werte ein MDM mitgeben kann -->
|
||||
<meta-data
|
||||
android:name="android.content.APP_RESTRICTIONS"
|
||||
android:resource="@xml/app_restrictions" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -27,6 +27,7 @@ class MainApplication : Application(), ReactApplication {
|
||||
add(BackgroundAudioPackage())
|
||||
add(ShareIntentPackage())
|
||||
add(TlsTrustPackage())
|
||||
add(MdmConfigPackage())
|
||||
}
|
||||
|
||||
override fun getJSMainModuleName(): String = "index"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.ariacockpit
|
||||
|
||||
import android.content.Context
|
||||
import android.content.RestrictionsManager
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.NativeModule
|
||||
import com.facebook.react.bridge.Promise
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import com.facebook.react.uimanager.ViewManager
|
||||
|
||||
/**
|
||||
* Verbindungsdaten aus dem MDM ("Managed Configuration" / App-Restrictions).
|
||||
*
|
||||
* Das MDM schreibt Schluessel/Werte fuer com.ariacockpit; welche es gibt,
|
||||
* steht in res/xml/app_restrictions.xml. Die App liest sie beim Start —
|
||||
* so muss beim Ausrollen niemand einen QR-Code scannen.
|
||||
*
|
||||
* Gibt nur die Schluessel zurueck, die das MDM wirklich gesetzt hat.
|
||||
*/
|
||||
class MdmConfigModule(ctx: ReactApplicationContext) : ReactContextBaseJavaModule(ctx) {
|
||||
override fun getName() = "MdmConfig"
|
||||
|
||||
@ReactMethod
|
||||
fun getConfig(promise: Promise) {
|
||||
try {
|
||||
val rm = reactApplicationContext.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
|
||||
val b = rm.applicationRestrictions
|
||||
val out = Arguments.createMap()
|
||||
for (key in b.keySet()) {
|
||||
when (val v = b.get(key)) {
|
||||
is String -> out.putString(key, v)
|
||||
is Int -> out.putInt(key, v)
|
||||
is Boolean -> out.putBoolean(key, v)
|
||||
}
|
||||
}
|
||||
promise.resolve(out)
|
||||
} catch (e: Exception) {
|
||||
promise.resolve(Arguments.createMap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MdmConfigPackage : ReactPackage {
|
||||
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
||||
listOf(MdmConfigModule(reactContext))
|
||||
|
||||
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
||||
emptyList()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Texte fuer die MDM-Werte (res/xml/app_restrictions.xml) -->
|
||||
<resources>
|
||||
<string name="mdm_host_title" translatable="false">RVS-Host</string>
|
||||
<string name="mdm_host_description" translatable="false">Hostname des RVS, z.B. aria-rvs.example.de</string>
|
||||
<string name="mdm_port_title" translatable="false">RVS-Port</string>
|
||||
<string name="mdm_tls_title" translatable="false">TLS verwenden</string>
|
||||
<string name="mdm_token_title" translatable="false">Token</string>
|
||||
<string name="mdm_token_description" translatable="false">Derselbe Token wie im QR-Code</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Werte, die ein MDM beim Ausrollen mitgeben kann (Managed Configuration).
|
||||
Sind host UND token gesetzt, verbindet sich die App damit — ohne QR-Code. -->
|
||||
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<restriction
|
||||
android:key="host"
|
||||
android:title="@string/mdm_host_title"
|
||||
android:description="@string/mdm_host_description"
|
||||
android:restrictionType="string" />
|
||||
<restriction
|
||||
android:key="port"
|
||||
android:title="@string/mdm_port_title"
|
||||
android:defaultValue="443"
|
||||
android:restrictionType="integer" />
|
||||
<restriction
|
||||
android:key="tls"
|
||||
android:title="@string/mdm_tls_title"
|
||||
android:defaultValue="true"
|
||||
android:restrictionType="bool" />
|
||||
<restriction
|
||||
android:key="token"
|
||||
android:title="@string/mdm_token_title"
|
||||
android:description="@string/mdm_token_description"
|
||||
android:restrictionType="string" />
|
||||
</restrictions>
|
||||
@@ -491,7 +491,40 @@ class RVSConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbindungsdaten aus dem MDM (Managed Configuration), falls beim Ausrollen
|
||||
* gesetzt. Nur gueltig mit host UND token. Schluessel: res/xml/app_restrictions.xml
|
||||
*/
|
||||
async loadMdmConfig(): Promise<ConnectionConfig | null> {
|
||||
try {
|
||||
const Mdm: any = NativeModules.MdmConfig;
|
||||
if (Platform.OS !== 'android' || !Mdm?.getConfig) return null;
|
||||
const m = await Mdm.getConfig();
|
||||
const host = String(m?.host ?? '').trim();
|
||||
const token = String(m?.token ?? '').trim();
|
||||
if (!host || !token) return null;
|
||||
const port = Number(m.port);
|
||||
return {
|
||||
host,
|
||||
token,
|
||||
port: Number.isFinite(port) && port > 0 ? port : 443,
|
||||
useTLS: m.tls !== false,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async loadConfig(): Promise<ConnectionConfig | null> {
|
||||
// Vom MDM gesetzte Werte haben Vorrang: so kommen geaenderte Zugangsdaten
|
||||
// beim naechsten App-Start an, ohne dass jemand am Geraet etwas tun muss.
|
||||
const mdm = await this.loadMdmConfig();
|
||||
if (mdm) {
|
||||
console.log('[RVS] Konfiguration aus dem MDM');
|
||||
this.config = mdm;
|
||||
await this.saveConfig(mdm);
|
||||
return mdm;
|
||||
}
|
||||
try {
|
||||
const data = await AsyncStorage.getItem(RVSConnection.STORAGE_KEY);
|
||||
if (data) {
|
||||
|
||||
Reference in New Issue
Block a user