From 94b78fd369c318baf1a98d4f510d791ea9f17017 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Thu, 16 Nov 2023 07:24:08 +0900 Subject: Update Kuksa databroker configuration scheme Rework Kuksa databroker configuration to also read a configuration yaml file from /etc/xdg/AGL/ics-homescreen.yaml at runtime to allow overriding the built-in default configuration. The latter is left as is with the addition of an explicit disabling of TLS, to still match the internal test setup at ICS. The AGL build will supply a runtime configuration that enables TLS and an authorization token. Additionally: - the ValClientHelper constructor has been changed to take the stub and authorization token as arguments to allow authorization with the VAL API requests. The channel argument has been removed since it is not used, only the stub is. - the apparently unused vss_provider.dart source file has been removed to avoid potential confusion. Bug-AGL: SPEC-4969 Change-Id: Ic7b867eaf565ef22f2e70df0afe7b5272b604d04 Signed-off-by: Scott Murray --- lib/core/constants/val_client_helper.dart | 10 +- lib/data/data_providers/vehicle_notifier.dart | 152 +++++++++++++++++++++++--- lib/data/data_providers/vss_provider.dart | 105 ------------------ lib/export.dart | 1 - 4 files changed, 144 insertions(+), 124 deletions(-) delete mode 100644 lib/data/data_providers/vss_provider.dart (limited to 'lib') diff --git a/lib/core/constants/val_client_helper.dart b/lib/core/constants/val_client_helper.dart index 0d7a284..02912b0 100644 --- a/lib/core/constants/val_client_helper.dart +++ b/lib/core/constants/val_client_helper.dart @@ -1,10 +1,10 @@ import 'package:protos/protos.dart'; class ValClientHelper { - final ClientChannel channel; final VALClient stub; + final String authorization; - ValClientHelper({required this.channel, required this.stub}); + ValClientHelper({required this.stub, required this.authorization}); void setUint32(String path, int value, [bool actuator = true]) async { var dp = Datapoint()..uint32 = value; @@ -50,9 +50,9 @@ class ValClientHelper { var request = SetRequest(); request.updates.add(update); Map metadata = {}; - // if (config.authorization.isNotEmpty) { - // metadata = {'authorization': "Bearer ${config.authorization}"}; - // } + if (authorization.isNotEmpty) { + metadata = {'authorization': "Bearer ${authorization}"}; + } await stub.set(request, options: CallOptions(metadata: metadata)); } } diff --git a/lib/data/data_providers/vehicle_notifier.dart b/lib/data/data_providers/vehicle_notifier.dart index b12cbfd..012e5dc 100644 --- a/lib/data/data_providers/vehicle_notifier.dart +++ b/lib/data/data_providers/vehicle_notifier.dart @@ -4,10 +4,28 @@ import 'package:flutter_ics_homescreen/export.dart'; import 'package:flutter/services.dart'; import 'package:protos/protos.dart'; +class KuksaConfig { + final String hostname; + final int port; + final String authorization; + final bool use_tls; + final List ca_certificate; + final String tls_server_name; + + static String configFilePath = '/etc/xdg/AGL/ics-homescreen.yaml'; + static String defaultHostname = 'localhost'; + static int defaultPort = 55555; + static String defaultCaCertPath = '/etc/kuksa-val/CA.pem'; + + KuksaConfig({required this.hostname, required this.port, required this.authorization, + required this.use_tls, required this.ca_certificate, required this.tls_server_name}); +} + class VehicleNotifier extends StateNotifier { VehicleNotifier(super.state); late ClientChannel channel; + late String authorization; late VALClient stub; void updateSpeed(double newValue) { @@ -123,33 +141,141 @@ class VehicleNotifier extends StateNotifier { } } - void startListen() async { - String hostName = 'localhost'; - int port = 8080; + Future readConfig() async { + String hostname = KuksaConfig.defaultHostname; + int port = KuksaConfig.defaultPort; + bool use_tls = false; + String ca_path = KuksaConfig.defaultCaCertPath; + List ca_cert = []; + String tls_server_name = ""; + String token = ""; + + // Read build time configuration from bundle try { var data = await rootBundle.loadString('app-config/config.yaml'); final dynamic yamlMap = loadYaml(data); if (yamlMap.containsKey('hostname')) { - hostName = yamlMap['hostname']; + hostname = yamlMap['hostname']; } if (yamlMap.containsKey('port')) { port = yamlMap['port']; } + + if (yamlMap.containsKey('use-tls')) { + var value = yamlMap['use-tls']; + if (value is bool) + use_tls = value; + } + + if (use_tls) { + if (yamlMap.containsKey('ca-certificate')) { + ca_path = yamlMap['ca-certificate']; + } + + if (yamlMap.containsKey('tls-server-name')) { + tls_server_name = yamlMap['tls_server_name']; + } + } + + if (yamlMap.containsKey('authorization')) { + token = yamlMap['authorization']; + } + } catch (e) { //debugPrint('ERROR: Could not read from file: $configFile'); debugPrint(e.toString()); } + + // Try reading from configuration file in /etc + final configFile = File(KuksaConfig.configFilePath); + try { + print("Reading configuration ${KuksaConfig.configFilePath}"); + String content = await configFile.readAsString(); + final dynamic yamlMap = loadYaml(content); + + if (yamlMap.containsKey('hostname')) { + hostname = yamlMap['hostname']; + } + + if (yamlMap.containsKey('port')) { + port = yamlMap['port']; + } + + if (yamlMap.containsKey('use-tls')) { + var value = yamlMap['use-tls']; + if (value is bool) + use_tls = value; + } + //debugPrint("Use TLS = $use_tls"); + + if (use_tls) { + if (yamlMap.containsKey('ca-certificate')) { + ca_path = yamlMap['ca-certificate']; + } + try { + ca_cert = File(ca_path).readAsBytesSync(); + } on Exception catch(_) { + print("ERROR: Could not read CA certificate file $ca_path"); + ca_cert = []; + } + //debugPrint("CA cert = $ca_cert"); + + if (yamlMap.containsKey('tls-server-name')) { + tls_server_name = yamlMap['tls_server_name']; + } + } + + if (yamlMap.containsKey('authorization')) { + token = yamlMap['authorization']; + } + if (token.isNotEmpty) { + if (token.startsWith("/")) { + debugPrint("Reading authorization token $token"); + String tokenFile = token; + try { + token = await File(tokenFile).readAsString(); + } on Exception catch(_) { + print("ERROR: Could not read authorization token file $token"); + token = ""; + } + } + } + //debugPrint("authorization = $token"); + } catch (e) { + debugPrint('WARNING: Could not read from file: $configFile'); + //debugPrint(e.toString()); + } + return KuksaConfig( + hostname: hostname, + port: port, + authorization: token, + use_tls: use_tls, + ca_certificate: ca_cert, + tls_server_name: tls_server_name + ); + } + + void startListen() async { + KuksaConfig config = await readConfig(); + ChannelCredentials creds; + if (config.use_tls && config.ca_certificate.isNotEmpty) { + print("Using TLS"); + if (config.tls_server_name.isNotEmpty) + creds = ChannelCredentials.secure(certificates: config.ca_certificate, + authority: config.tls_server_name); + else + creds = ChannelCredentials.secure(certificates: config.ca_certificate); + } else { + creds = ChannelCredentials.insecure(); + } channel = ClientChannel( - hostName, - port: port, - options: const ChannelOptions( - credentials: ChannelCredentials.insecure(), - ), + config.hostname, + port: config.port, + options: ChannelOptions(credentials: creds) ); - - debugPrint('Start Listen on port: $port'); + debugPrint('Start Listen on port: ${config.port}'); stub = VALClient(channel); List fewSignals = VSSPath().getSignalsList(); var request = SubscribeRequest(); @@ -183,7 +309,7 @@ class VehicleNotifier extends StateNotifier { } void setChildLock({required String side}) { - var helper = ValClientHelper(channel: channel, stub: stub); + var helper = ValClientHelper(stub: stub, authorization: authorization); try { switch (side) { case 'left': @@ -218,7 +344,7 @@ class VehicleNotifier extends StateNotifier { } void setHVACMode({required String mode}) { - var helper = ValClientHelper(channel: channel, stub: stub); + var helper = ValClientHelper(stub: stub, authorization: authorization); try { switch (mode) { case 'airCondition': diff --git a/lib/data/data_providers/vss_provider.dart b/lib/data/data_providers/vss_provider.dart deleted file mode 100644 index ca02de6..0000000 --- a/lib/data/data_providers/vss_provider.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:flutter_ics_homescreen/export.dart'; -import 'package:protos/protos.dart'; - -class VSS { - static handleSignalUpdates( - EntryUpdate update, - ) { - //final ref = ProviderContainer().read(vehicleStateProvider); - switch (update.entry.path) { - case VSSPath.vehicleSpeed: - if (update.entry.value.hasFloat()) { - //print(ref); - } - break; - // case VSSPath.vehicleInsideTemperature: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleInsideTemperature.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleOutsideTemperature: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleOutSideTemperature.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleRange: - // if (update.entry.value.hasInt32()) { - // ref - // .read(vehicleRange.notifier) - // .update((state) => state = update.entry.value.uint32); - // } - // break; - // case VSSPath.vehicleFuelLevel: - // if (update.entry.value.hasInt32()) { - // ref - // .read(vehicleFuelLevel.notifier) - // .update((state) => state = update.entry.value.uint32); - // } - // break; - // case VSSPath.vehicleMediaVolume: - // if (update.entry.value.hasInt32()) { - // ref - // .read(vehicleMediaVolume.notifier) - // .update((state) => state = update.entry.value.uint32); - // } - // break; - // case VSSPath.vehicleIsChildLockActiveLeft: - // if (update.entry.value.hasBool_12()) { - // ref - // .read(vehicleIsChildLockActiveLeft.notifier) - // .update((state) => state = update.entry.value.bool_12); - // } - // break; - // case VSSPath.vehicleIsChildLockActiveRight: - // if (update.entry.value.hasBool_12()) { - // ref - // .read(vehicleIsChildLockActiveRight.notifier) - // .update((state) => state = update.entry.value.bool_12); - // } - // break; - // case VSSPath.vehicleEngineSpeed: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleEngineSpeed.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleFrontLeftTire: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleFrontLeftTire.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleFrontRightTire: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleFrontRightTire.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleRearLeftTire: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleRearLeftTire.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - // case VSSPath.vehicleRearRightTire: - // if (update.entry.value.hasFloat()) { - // ref - // .read(vehicleRearRightTire.notifier) - // .update((state) => state = update.entry.value.float); - // } - // break; - - default: - debugPrint("ERROR: Unexpected path ${update.entry.path}"); - break; - } - } -} diff --git a/lib/export.dart b/lib/export.dart index 08dff4f..20aa850 100644 --- a/lib/export.dart +++ b/lib/export.dart @@ -1,7 +1,6 @@ export 'data/data_providers/app.dart'; export 'data/data_providers/app_provider.dart'; export 'presentation/router/routes/routes.dart'; -export 'data/data_providers/vss_provider.dart'; export 'data/theme/theme.dart'; //Models -- cgit 1.2.3-korg