From 3ab5636a1ae6f29dde71afbb40ab457aebcb8c8c Mon Sep 17 00:00:00 2001 From: Chralu Date: Wed, 13 Dec 2023 09:05:23 +0100 Subject: [PATCH] WIP --- assets/ssl/private_key.pem | 28 +++ assets/ssl/server.crt | 19 ++ lib/infrastructure/rpc/websocket_server.dart | 222 +++++++++++------- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.yaml | 5 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 7 files changed, 197 insertions(+), 83 deletions(-) create mode 100644 assets/ssl/private_key.pem create mode 100644 assets/ssl/server.crt diff --git a/assets/ssl/private_key.pem b/assets/ssl/private_key.pem new file mode 100644 index 000000000..80763be57 --- /dev/null +++ b/assets/ssl/private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC90vMC8TGOoiEh +so5bAYdE8C1P+bt2deqs2oMgqZBF5+3gkvvp7kEij/x2nKKnBlJ/1a7lJXIjEdp8 +LNuvCeTzy1pdHZf8MzMhVLWHYO8xoGAJHPVBpbE4KDrxXoSY01f15wasRcqBgUYx +pMB7QqDG49PMheyvg92KhMh73ZXZZWyjDA8UjfmbCkTZTn2rQTloTMP8tL50/lWW +y86dJOshke5Nb14xVLNruTKOPy05RwgbcMz7WKD02xkBv8s+i7i0yl7Tyh8g/V/7 +8ILpeqFyMq4DXFLCC8wDrnjHoNc/ThO5IdW595lSSr7T018bZ1GfIx+jGV2yF1Hf +OvWYmBI9AgMBAAECggEAKilLvOxN7ciAc9/ZIwj+nrb61X/aHZhYsJ5TECLhTsmS +CfaTmdSHppHVCRJGxTLQCaEwOKidxoDNZpW/EIxxzB1vW226h3NmyKEsNZ632e2t +TvDd34AaEedLmjc8W8ZbS9yNnJ9euG96ZAXcE7SLiclqDkvzs1MmVoEiF3LyuMde +I6GwvSFsLtUzHW6fx8j8c0VnbXI7PzF4zevLnrDfHK2edatB0P0Wh2jl6xOZQo4o +WL0N4R05583cJYhuOJll14H+0G0sRqUeot+Fb9GbwBR0IGUuw0//3Qq2TbHi3OJq +rJ3GaAPeWCYzJjY/gPkIHhx5iaD8LmeXDQXQ9433OQKBgQDyIlsK4cO+jk+Eq+08 +YuJrMxCtLYe22tMVjFqh/McMu2M3ATZZD6b06MGdmYJhTPTfRGmyw5VsYg+pzfE7 +6zNk+3zMjUykar6n56qDe2DwAX9eOkIol8PPbN8K/lb0AQv5wRAvn8trIbchz6QV +8q1tKiyupe1BMGCerN116+OG5QKBgQDIsbxU3BQ+hMaR7hkNbd6r8a1RtMnM/Zsp +DDiULJnKeyaegz58Rj9+5k7q0gDCgutetMmmy869921JtXldPeeJ4U6w+Giin9CO +6sUVmwsC3m9cYWZUvAUFcqMRiRxK4NlZIKf2zbsAicJeDV8NcpB2+uK5SX2PUhQ8 +qKKo2jMQeQKBgBOPLueMITHNcSL4eGt+WWfrchdrLCFbP93nvpKDRtkCchtJX8iF ++SijfLBsbBnMC6PVdOxZ3EIrEbTXy/rZHwezQPuNFnnZnZkWn7GLT+NTW6SS9DEv +QUQKOWI79W40f3EnZVVThS0cRhzXFxwmxFejJoTdJnMzozpuIF2cNn75AoGAQsxN +h90ca9ablPSvp/WauJYe/uPyiuUaIKZtqnvR0D//EaFTSd/DwIP9XlD5acRTfNkl +iPuq2zWgTXk2ZN920kCIhYSYpxAURY1EfbV2C8VnQVM10Rwne7G1Lt/4579A+FZT +MWU2Sa6QX+eJbJtmFAPbNJqOTQafr7TdNuAxQNkCgYA+RaFqihahSHygc7cdllvJ +8UjzcIF/71BE/9RPm3Cqo25fBkL4LQOPfWQewl8zTZ+CsQVdJnVKNMcM/G1sroJa +sJ2XgHJJ1zaI/rwaE5Jxf6lH4fL7uL2BDR7s3VLDs8BRWrcrgdNzb+UWhXJICnz5 +bK3qk9vzRjMv+8g5zolPJQ== +-----END PRIVATE KEY----- diff --git a/assets/ssl/server.crt b/assets/ssl/server.crt new file mode 100644 index 000000000..779f6f8c6 --- /dev/null +++ b/assets/ssl/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfkCFDuB9EvVQQhQQjxiaMFD6Ze3tpDbMA0GCSqGSIb3DQEBCwUAMEUx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjMxMjA2MDc0MTI2WhcNMjQxMjA1MDc0 +MTI2WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE +CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAvdLzAvExjqIhIbKOWwGHRPAtT/m7dnXqrNqDIKmQReft4JL7 +6e5BIo/8dpyipwZSf9Wu5SVyIxHafCzbrwnk88taXR2X/DMzIVS1h2DvMaBgCRz1 +QaWxOCg68V6EmNNX9ecGrEXKgYFGMaTAe0KgxuPTzIXsr4PdioTIe92V2WVsowwP +FI35mwpE2U59q0E5aEzD/LS+dP5VlsvOnSTrIZHuTW9eMVSza7kyjj8tOUcIG3DM ++1ig9NsZAb/LPou4tMpe08ofIP1f+/CC6XqhcjKuA1xSwgvMA654x6DXP04TuSHV +ufeZUkq+09NfG2dRnyMfoxldshdR3zr1mJgSPQIDAQABMA0GCSqGSIb3DQEBCwUA +A4IBAQCBMvhMmAp1Y08XtNoaaEJv9KIaNkrbvbZzJlVbvrUDDAq0/DU4B6EA3V4U +8tFsfZpmqWpoMspINYT/EgHYK1idkh2TRyCA94XdSw4g3g0iuwoDJRnvTTkXbge9 +BIac4jOmS44VvrzT9OCH7W8AB4P0vTM3Nssu3kIQz/VDSuv7Ypfvvl4O8XP9PTym +cjjrs83iomOcinONzM6MIvUHe+n8nODbsxLcqQZbZIn+jcKprUVZYT4Cbq1HeanP +QU71lxR6YmRARmuHYpN3VKTpkQKSC5BEXPfSuRzTFUsH8f0JDWxg4VV+oLiINrRL +8qrX+XeZPZHXkeqR61QUxCAUFkV7 +-----END CERTIFICATE----- diff --git a/lib/infrastructure/rpc/websocket_server.dart b/lib/infrastructure/rpc/websocket_server.dart index 104b63582..e8ada65d9 100644 --- a/lib/infrastructure/rpc/websocket_server.dart +++ b/lib/infrastructure/rpc/websocket_server.dart @@ -19,7 +19,9 @@ import 'package:aewallet/infrastructure/rpc/sign_transactions/command_handler.da import 'package:aewallet/infrastructure/rpc/sub_account/command_handler.dart'; import 'package:aewallet/infrastructure/rpc/sub_current_account/command_handler.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:json_rpc_2/json_rpc_2.dart'; +import 'package:nsd/nsd.dart'; import 'package:web_socket_channel/io.dart'; /// A [Peer] composition which handles subscription requests @@ -101,9 +103,12 @@ class ArchethicWebsocketRPCServer { ArchethicWebsocketRPCServer(); static const logName = 'RPC Server'; - static const host = '127.0.0.1'; + static const name = 'archethic_wallet'; + static const host = 'localhost'; static const port = 12345; + Registration? mDnsRegistration; + static bool get isPlatformCompatible { return !kIsWeb && (Platform.isLinux || Platform.isMacOS || Platform.isWindows); @@ -114,6 +119,34 @@ class ArchethicWebsocketRPCServer { bool get isRunning => _openedSockets.isNotEmpty || _runningHttpServer != null; + Future> _loadBundleIntList(String asset) async { + final byteData = await rootBundle.load(asset); + return byteData.buffer.asInt8List(); + } + + Future _setupServerContext() async { + final serverContext = SecurityContext() + ..useCertificateChainBytes( + await _loadBundleIntList('assets/ssl/server.crt'), + ) + ..usePrivateKeyBytes( + await _loadBundleIntList('assets/ssl/private_key.pem'), + ); + return serverContext; + } + + Future mDnsRegister() async { + mDnsRegistration = await register( + const Service(name: name, type: '_http._tcp', port: port), + ); + } + + Future mDnsUnRegister() async { + if (mDnsRegistration == null) return; + await unregister(mDnsRegistration!); + mDnsRegistration = null; + } + Future run() async { runZonedGuarded( () async { @@ -122,89 +155,109 @@ class ArchethicWebsocketRPCServer { return; } - log('Starting at ws://$host:$port', name: logName); - final httpServer = await HttpServer.bind( - host, - port, - shared: true, - ); + log('Starting at wss://$host:$port', name: logName); + + try { + final httpServer = await HttpServer.bindSecure( + host, + port, + await _setupServerContext(), + shared: true, + ); + // final httpServer = await HttpServer.bind( + // host, + // port, + // shared: true, + // ); + httpServer.listen((HttpRequest request) async { + log('Received request', name: logName); + + final socket = await WebSocketTransformer.upgrade(request); + final channel = IOWebSocketChannel(socket); + + final peerServer = _SubscribablePeer(Peer(channel.cast())) + ..registerMethod( + 'sendTransaction', + (params) => _handle(RPCSendTransactionCommandHandler(), params), + ) + ..registerMethod( + 'getEndpoint', + (params) => _handle(RPCGetEndpointCommandHandler(), params), + ) + ..registerMethod( + 'refreshCurrentAccount', + (params) => + _handle(RPCRefreshCurrentAccountCommandHandler(), params), + ) + ..registerMethod( + 'getCurrentAccount', + (params) => + _handle(RPCGetCurrentAccountCommandHandler(), params), + ) + ..registerMethod( + 'getAccounts', + (params) => _handle(RPCGetAccountsCommandHandler(), params), + ) + ..registerSubscriptionMethod( + 'subscribeAccount', + (params) => _handleSubscription( + RPCSubscribeAccountCommandHandler(), + params, + ), + ) + ..registerUnsubscriptionMethod( + 'unsubscribeAccount', + ) + ..registerSubscriptionMethod( + 'subscribeCurrentAccount', + (params) => _handleSubscription( + RPCSubscribeCurrentAccountCommandHandler(), + params, + ), + ) + ..registerUnsubscriptionMethod( + 'unsubscribeCurrentAccount', + ) + ..registerMethod( + 'addService', + (params) => _handle(RPCAddServiceCommandHandler(), params), + ) + ..registerMethod( + 'getServicesFromKeychain', + (params) => + _handle(RPCGetServicesFromKeychainCommandHandler(), params), + ) + ..registerMethod( + 'keychainDeriveKeypair', + (params) => + _handle(RPCKeychainDeriveKeypairCommandHandler(), params), + ) + ..registerMethod( + 'keychainDeriveAddress', + (params) => + _handle(RPCKeychainDeriveAddressCommandHandler(), params), + ) + ..registerMethod( + 'signTransactions', + (params) => + _handle(RPCSignTransactionsCommandHandler(), params), + ); + + _openedSockets.add(peerServer); + await peerServer.listen(); + }); + _runningHttpServer = httpServer; + } catch (error, stack) { + log( + 'WebSocket server failed', + error: error, + stackTrace: stack, + name: logName, + ); + } - httpServer.listen((HttpRequest request) async { - log('Received request', name: logName); - - final socket = await WebSocketTransformer.upgrade(request); - final channel = IOWebSocketChannel(socket); - - final peerServer = _SubscribablePeer(Peer(channel.cast())) - ..registerMethod( - 'sendTransaction', - (params) => _handle(RPCSendTransactionCommandHandler(), params), - ) - ..registerMethod( - 'getEndpoint', - (params) => _handle(RPCGetEndpointCommandHandler(), params), - ) - ..registerMethod( - 'refreshCurrentAccount', - (params) => - _handle(RPCRefreshCurrentAccountCommandHandler(), params), - ) - ..registerMethod( - 'getCurrentAccount', - (params) => _handle(RPCGetCurrentAccountCommandHandler(), params), - ) - ..registerMethod( - 'getAccounts', - (params) => _handle(RPCGetAccountsCommandHandler(), params), - ) - ..registerSubscriptionMethod( - 'subscribeAccount', - (params) => _handleSubscription( - RPCSubscribeAccountCommandHandler(), - params, - ), - ) - ..registerUnsubscriptionMethod( - 'unsubscribeAccount', - ) - ..registerSubscriptionMethod( - 'subscribeCurrentAccount', - (params) => _handleSubscription( - RPCSubscribeCurrentAccountCommandHandler(), - params, - ), - ) - ..registerUnsubscriptionMethod( - 'unsubscribeCurrentAccount', - ) - ..registerMethod( - 'addService', - (params) => _handle(RPCAddServiceCommandHandler(), params), - ) - ..registerMethod( - 'getServicesFromKeychain', - (params) => - _handle(RPCGetServicesFromKeychainCommandHandler(), params), - ) - ..registerMethod( - 'keychainDeriveKeypair', - (params) => - _handle(RPCKeychainDeriveKeypairCommandHandler(), params), - ) - ..registerMethod( - 'keychainDeriveAddress', - (params) => - _handle(RPCKeychainDeriveAddressCommandHandler(), params), - ) - ..registerMethod( - 'signTransactions', - (params) => _handle(RPCSignTransactionsCommandHandler(), params), - ); - - _openedSockets.add(peerServer); - await peerServer.listen(); - }); - _runningHttpServer = httpServer; + log('mDns registration', name: logName); + await mDnsRegister(); }, (error, stack) { log( @@ -235,6 +288,9 @@ class ArchethicWebsocketRPCServer { await _runningHttpServer?.close(); _runningHttpServer = null; log('Server stopped at ws://$host:$port', name: logName); + + log('mDns unregistration', name: logName); + await mDnsUnRegister(); }, (error, stack) { log( diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index e2fd89d51..72a208811 100755 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -12,6 +12,7 @@ import firebase_core import firebase_messaging import flutter_local_notifications import flutter_secure_storage_macos +import nsd_macos import package_info_plus import path_provider_foundation import pdfx @@ -29,6 +30,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + NsdMacosPlugin.register(with: registry.registrar(forPlugin: "NsdMacosPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PdfxPlugin.register(with: registry.registrar(forPlugin: "PdfxPlugin")) diff --git a/pubspec.yaml b/pubspec.yaml index 264b864c6..83b04e135 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -186,6 +186,9 @@ dependencies: # Get Mime Types, Extensions, Compressible for Dart and Flutter. Inspired from IANA Database mime_dart: ^3.0.0 + # mDNS registration + nsd: ^2.3.1 + # Flutter plugin for accessing the NFC features on Android and iOS. nfc_manager: ^3.3.0 @@ -311,6 +314,8 @@ flutter: assets: - assets/ssl/isrg-root-x1.pem + - assets/ssl/private_key.pem + - assets/ssl/server.crt - assets/icons/ - assets/icons/currency/ - assets/icons/languages/ diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 569231074..7b6b6b1ab 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); LocalAuthPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("LocalAuthPlugin")); + NsdWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("NsdWindowsPluginCApi")); PdfxPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PdfxPlugin")); ScreenRetrieverPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e4cd45f8a..62c5fd44c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST firebase_core flutter_secure_storage_windows local_auth_windows + nsd_windows pdfx screen_retriever share_plus