diff --git a/android/src/main/kotlin/net/archethic/yubikit_android/methods/Connect.kt b/android/src/main/kotlin/net/archethic/yubikit_android/methods/Connect.kt new file mode 100644 index 0000000..9a53d0b --- /dev/null +++ b/android/src/main/kotlin/net/archethic/yubikit_android/methods/Connect.kt @@ -0,0 +1,10 @@ +package net.archethic.yubikit_android.methods + +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel + +class Connect : MethodHandler { + override fun handle(call: MethodCall, result: MethodChannel.Result) { + + } +} diff --git a/android/src/main/kotlin/net/archethic/yubikit_android/methods/MethodHandler.kt b/android/src/main/kotlin/net/archethic/yubikit_android/methods/MethodHandler.kt new file mode 100644 index 0000000..fec517d --- /dev/null +++ b/android/src/main/kotlin/net/archethic/yubikit_android/methods/MethodHandler.kt @@ -0,0 +1,9 @@ +package net.archethic.yubikit_android.methods + +import androidx.annotation.NonNull +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel + +interface MethodHandler { + fun handle(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result); +} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index e7c9182..0969b27 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -36,4 +36,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 57e587b..6184a29 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -205,6 +205,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -241,6 +242,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -361,8 +363,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = T3ZV8MV4P2; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -371,6 +374,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = net.archethic.example; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -491,8 +495,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = T3ZV8MV4P2; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -501,6 +506,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = net.archethic.example; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -515,8 +521,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = T3ZV8MV4P2; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -525,6 +532,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = net.archethic.example; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/example/lib/components/capabilities_text.dart b/example/lib/components/capabilities_text.dart index d38f1c9..f6612b1 100644 --- a/example/lib/components/capabilities_text.dart +++ b/example/lib/components/capabilities_text.dart @@ -24,7 +24,7 @@ class CapabilitiesText extends StatelessWidget { Future capabilitiesString() async { try { - final capabilities = await yubikitPlugin.general.deviceCapabilities; + final capabilities = await yubikitPlugin.connection.deviceCapabilities; return 'nfc : ${capabilities.nfc}, wired : ${capabilities.wired}'; } on PlatformException { return 'Failed to get device capabilities'; diff --git a/example/lib/components/generate_key_button.dart b/example/lib/components/generate_key_button.dart index e5502a0..c5051a7 100644 --- a/example/lib/components/generate_key_button.dart +++ b/example/lib/components/generate_key_button.dart @@ -14,12 +14,20 @@ class GenerateKeyButton extends StatelessWidget { Widget build(BuildContext context) => ActionButton( text: 'Generate key', onPressed: () async { - final publicKey = await yubikitPlugin.piv.generateKey( - pin: "123456", - managementKey: PivManagementKey.fromString( + final connection = await yubikitPlugin.connection.connect( + timeout: const Duration(seconds: 15), + ); + final piv = await connection.pivSession; + + await piv.verifyPin("123456"); + await piv.authenticate( + PivManagementKey.fromString( "010203040506070801020304050607080102030405060708", keyType: PivManagementKeyType.tripleDES, ), + ); + + final publicKey = await piv.generateKey( pinPolicy: PivPinPolicy.defaultPolicy, type: PivKeyType.eccp256, touchPolicy: PivTouchPolicy.defaultPolicy, diff --git a/example/lib/components/piv_calculate_secret_button.dart b/example/lib/components/piv_calculate_secret_button.dart index a42f69a..d7f38ca 100644 --- a/example/lib/components/piv_calculate_secret_button.dart +++ b/example/lib/components/piv_calculate_secret_button.dart @@ -14,9 +14,13 @@ class PivCalculateSecretButton extends StatelessWidget { Widget build(BuildContext context) => ActionButton( text: 'Calculate secret', onPressed: () async { - final secret = await yubikitPlugin.piv.calculateSecret( + final connection = await yubikitPlugin.connection.connect(); + final piv = await connection.pivSession; + + piv.verifyPin("123456"); + + final secret = await piv.calculateSecret( slot: PivSlot.authentication, - pin: "123456", peerPublicKey: """ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElqeFrBCjtonol5ksKYCuXf+alUTI diff --git a/example/lib/components/piv_read_cert_button.dart b/example/lib/components/piv_read_cert_button.dart index 8d28259..97754fa 100644 --- a/example/lib/components/piv_read_cert_button.dart +++ b/example/lib/components/piv_read_cert_button.dart @@ -14,8 +14,10 @@ class PivReadCertButton extends StatelessWidget { Widget build(BuildContext context) => ActionButton( text: 'Read certificate', onPressed: () async { - final publicKey = await yubikitPlugin.piv.getCertificate( - pin: "123456", + final connection = await yubikitPlugin.connection.connect(); + final piv = await connection.pivSession; + await piv.verifyPin("123456"); + final publicKey = await piv.getCertificate( slot: PivSlot.signature, ); return publicKey.toString(); diff --git a/example/pubspec.lock b/example/pubspec.lock index 59fc579..7e54cb2 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,70 +5,80 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" cryptography: dependency: transitive description: name: cryptography - url: "https://pub.dartlang.org" + sha256: e0e37f79665cd5c86e8897f9abe1accfe813c0cc5299dab22256e22fddc1fef8 + url: "https://pub.dev" source: hosted version: "2.0.5" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + url: "https://pub.dev" source: hosted version: "1.0.1" flutter: @@ -80,7 +90,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -92,98 +103,112 @@ packages: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted version: "0.6.5" jwk: dependency: "direct main" description: name: jwk - url: "https://pub.dartlang.org" + sha256: "90a38db729726443e687e7620f5ee0b2a41b0670b3a6eee43a84fdf2e0ea643b" + url: "https://pub.dev" source: hosted version: "0.1.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" nfc_manager: dependency: transitive description: name: nfc_manager - url: "https://pub.dartlang.org" + sha256: cff1e59e316388f4508b4ba0cea4430e4ba39f8a68ecfb3e1256be25c13b0f4a + url: "https://pub.dev" source: hosted version: "3.2.0" nonce: dependency: transitive description: name: nonce - url: "https://pub.dartlang.org" + sha256: bd279f698c9f641a64375a17040bd899061e46bdb9aa65bf846838bd3b8b437f + url: "https://pub.dev" source: hosted version: "1.2.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" pem: dependency: "direct main" description: name: pem - url: "https://pub.dartlang.org" + sha256: cb26251e772e00c5b7b9414a344025b50de2324c22a76aa8f993f3dfab3acde9 + url: "https://pub.dev" source: hosted version: "2.0.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted version: "5.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" sky_engine: @@ -195,58 +220,66 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" yubidart: dependency: "direct main" description: diff --git a/ios/Classes/handlers/PivCalculateSecret.swift b/ios/Classes/handlers/PivCalculateSecret.swift index d75a256..908d18f 100644 --- a/ios/Classes/handlers/PivCalculateSecret.swift +++ b/ios/Classes/handlers/PivCalculateSecret.swift @@ -56,7 +56,6 @@ class PivCalculateSecretHandler: Handler { return } - pivSession.verifyPin(pin) { retries, verifyPinError in guard verifyPinError == nil else { context.failure( diff --git a/lib/src/domain/protocol/connection/protocol.dart b/lib/src/domain/protocol/connection/protocol.dart new file mode 100644 index 0000000..d803340 --- /dev/null +++ b/lib/src/domain/protocol/connection/protocol.dart @@ -0,0 +1,18 @@ +import 'package:yubidart/yubidart.dart'; + +abstract class Connection { + Future get pivSession; + + Future get otpSession; +} + +abstract class ConnectionProtocol { + /// Looks at the device capabilities (connectivity mainly) + Future get deviceCapabilities; + + Future connect({ + Duration timeout = const Duration(minutes: 1), + }); + + Future disconnect(); +} diff --git a/lib/src/domain/protocol/general/protocol.dart b/lib/src/domain/protocol/general/protocol.dart deleted file mode 100644 index bad1961..0000000 --- a/lib/src/domain/protocol/general/protocol.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:yubidart/src/domain/model/general/device_capabilities.dart'; - -abstract class GeneralProtocol { - /// Looks at the device capabilities (connectivity mainly) - Future get deviceCapabilities; -} diff --git a/lib/src/domain/protocol/piv/protocol.dart b/lib/src/domain/protocol/piv/protocol.dart index 5098071..0d1edb7 100644 --- a/lib/src/domain/protocol/piv/protocol.dart +++ b/lib/src/domain/protocol/piv/protocol.dart @@ -6,6 +6,16 @@ import 'package:yubidart/src/domain/model/piv/slot.dart'; import 'package:yubidart/src/domain/model/piv/touch_policy.dart'; abstract class PivProtocol { + /// Verifies the PIN code. + /// + /// [pin] The pin. Default pin code is 123456. + Future verifyPin(String pin); + + /// Authenticates with the management key + /// + /// [managementKey] The management key. Default value is 000102030405060708090A0B0C0D0E0F1011121314151617. + Future authenticate(PivManagementKey managementKey); + /// Generates a new key pair within the YubiKey. /// This method requires authentication and pin verification. /// @@ -16,7 +26,6 @@ abstract class PivProtocol { /// TouchPolicy.CACHED requires support for touch cached, available on YubiKey 4.3 or later. /// This method is thread safe and can be invoked from any thread (main or a background thread). /// - /// [pin] The pin. Default pin code is 123456. /// [slot] The slot to generate the new key in. /// [type] Which algorithm is used for key generation. /// [pinPolicy] The PIN policy for using the private key. @@ -24,8 +33,6 @@ abstract class PivProtocol { /// /// Throws a [YKFailure] Future generateKey({ - required String pin, - required PivManagementKey managementKey, required PivSlot slot, required PivKeyType type, required PivPinPolicy pinPolicy, @@ -34,24 +41,20 @@ abstract class PivProtocol { /// Reads the X.509 certificate stored in the specified slot on the YubiKey. /// - /// [pin] The pin. Default pin code is 123456. /// [slot] : The slot where the certificate is stored. /// /// Throws a [YKFailure] Future getCertificate({ - required String pin, required PivSlot slot, }); /// Perform an ECDH operation with a given public key to compute a shared secret. /// - /// [pin] The pin. Default pin code is 123456. /// [slot] The slot containing the private EC key to use. /// [peerPublicKey] The peer public key for the operation. This is an EllipticCurve encryption public key in PEM format. /// /// Throws a [YKFailure] Future calculateSecret({ - required String pin, required PivSlot slot, required String peerPublicKey, }); diff --git a/lib/src/domain/protocol/protocol.dart b/lib/src/domain/protocol/protocol.dart index e0ad23a..78f6e49 100644 --- a/lib/src/domain/protocol/protocol.dart +++ b/lib/src/domain/protocol/protocol.dart @@ -1,3 +1,3 @@ -export 'general/protocol.dart'; +export 'connection/protocol.dart'; export 'otp/otp.dart'; export 'piv/protocol.dart'; diff --git a/lib/src/domain/yubidart_platform_interface.dart b/lib/src/domain/yubidart_platform_interface.dart index 7c0527a..529149c 100644 --- a/lib/src/domain/yubidart_platform_interface.dart +++ b/lib/src/domain/yubidart_platform_interface.dart @@ -1,6 +1,5 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:yubidart/src/domain/protocol/general/protocol.dart'; -import 'package:yubidart/src/domain/protocol/piv/protocol.dart'; +import 'package:yubidart/src/domain/protocol/connection/protocol.dart'; abstract class YubidartPlatform extends PlatformInterface { /// Constructs a [YubidartPlatform]. @@ -15,9 +14,7 @@ abstract class YubidartPlatform extends PlatformInterface { /// Defaults to [MethodChannelYubidart]. static YubidartPlatform get instance => _instance; - PivProtocol get piv; - - GeneralProtocol get general; + ConnectionProtocol get connection; /// Platform-specific implementations should set this with their own /// platform-specific class that extends [YubidartPlatform] when @@ -30,8 +27,5 @@ abstract class YubidartPlatform extends PlatformInterface { class EmptyYubidartPlatformImplementation implements YubidartPlatform { @override - GeneralProtocol get general => throw UnimplementedError(); - - @override - PivProtocol get piv => throw UnimplementedError(); + ConnectionProtocol get connection => throw UnimplementedError(); } diff --git a/lib/src/infrastructure/protocol/connection/default_connection_protocol.dart b/lib/src/infrastructure/protocol/connection/default_connection_protocol.dart new file mode 100644 index 0000000..cc05e73 --- /dev/null +++ b/lib/src/infrastructure/protocol/connection/default_connection_protocol.dart @@ -0,0 +1,72 @@ +import 'package:flutter/services.dart'; +import 'package:yubidart/src/domain/model/failure/failure.dart'; +import 'package:yubidart/src/domain/model/general/device_capabilities.dart'; +import 'package:yubidart/src/domain/protocol/connection/protocol.dart'; +import 'package:yubidart/src/domain/protocol/otp/otp.dart'; +import 'package:yubidart/src/domain/protocol/piv/protocol.dart'; +import 'package:yubidart/src/infrastructure/protocol/otp/default_otp_protocol.dart'; +import 'package:yubidart/src/infrastructure/protocol/otp/yubicloud_client.dart'; +import 'package:yubidart/src/infrastructure/protocol/piv/default_piv_protocol.dart'; + +class DefaultConnection implements Connection { + @override + Future get pivSession async => DefaultPivProtocol(); + + @override + Future get otpSession async => + DefaultOTPProtocol(yubicloudClient: YubicloudClient()); +} + +class DefaultConnectionProtocol implements ConnectionProtocol { + /// The method channel used to interact with the native platform. + // @foundation.visibleForTesting + final methodChannel = const MethodChannel('net.archethic/yubidart'); + + @override + Future get deviceCapabilities => YKFailure.guard( + () async { + final supportsNFCScanning = + await methodChannel.invokeMethod('supportsNFCScanning'); + final supportsISO7816NFCTags = + await methodChannel.invokeMethod('supportsISO7816NFCTags'); + final supportsMFIAccessoryKey = + await methodChannel.invokeMethod('supportsMFIAccessoryKey'); + + if (supportsNFCScanning == null || + supportsISO7816NFCTags == null || + supportsMFIAccessoryKey == null) { + throw YKFailure.other(); + } + + return DeviceCapabilities( + nfc: supportsNFCScanning || supportsISO7816NFCTags, + wired: supportsMFIAccessoryKey, + ); + }, + ); + + @override + Future connect({ + Duration timeout = const Duration(minutes: 1), + }) { + return YKFailure.guard( + () async { + await methodChannel.invokeMethod( + 'connect', + ); + return DefaultConnection(); + }, + ); + } + + @override + Future disconnect() { + return YKFailure.guard( + () async { + await methodChannel.invokeMethod( + 'disconnect', + ); + }, + ); + } +} diff --git a/lib/src/infrastructure/protocol/general/default_general_protocol.dart b/lib/src/infrastructure/protocol/general/default_general_protocol.dart deleted file mode 100644 index e289c4e..0000000 --- a/lib/src/infrastructure/protocol/general/default_general_protocol.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:yubidart/src/domain/model/model.dart'; -import 'package:yubidart/src/domain/protocol/general/protocol.dart'; - -class DefaultGeneralProtocol implements GeneralProtocol { - /// The method channel used to interact with the native platform. - // @foundation.visibleForTesting - final methodChannel = const MethodChannel('net.archethic/yubidart'); - - @override - Future get deviceCapabilities => YKFailure.guard( - () async { - final supportsNFCScanning = - await methodChannel.invokeMethod('supportsNFCScanning'); - final supportsISO7816NFCTags = - await methodChannel.invokeMethod('supportsISO7816NFCTags'); - final supportsMFIAccessoryKey = - await methodChannel.invokeMethod('supportsMFIAccessoryKey'); - - if (supportsNFCScanning == null || - supportsISO7816NFCTags == null || - supportsMFIAccessoryKey == null) { - throw YKFailure.other(); - } - - return DeviceCapabilities( - nfc: supportsNFCScanning || supportsISO7816NFCTags, - wired: supportsMFIAccessoryKey, - ); - }, - ); -} diff --git a/lib/src/infrastructure/protocol/piv/default_piv_protocol.dart b/lib/src/infrastructure/protocol/piv/default_piv_protocol.dart index 57c8698..040c86e 100644 --- a/lib/src/infrastructure/protocol/piv/default_piv_protocol.dart +++ b/lib/src/infrastructure/protocol/piv/default_piv_protocol.dart @@ -14,8 +14,6 @@ class DefaultPivProtocol implements PivProtocol { @override Future generateKey({ - required String pin, - required PivManagementKey managementKey, required PivSlot slot, required PivKeyType type, required PivPinPolicy pinPolicy, @@ -26,9 +24,6 @@ class DefaultPivProtocol implements PivProtocol { final result = await methodChannel.invokeMethod( 'pivGenerateKey', { - 'pin': pin, - 'managementKey': managementKey.key, - 'managementKeyType': managementKey.keyType.value, 'slot': slot.value, 'type': type.value, 'pinPolicy': pinPolicy.value, @@ -45,7 +40,6 @@ class DefaultPivProtocol implements PivProtocol { @override Future getCertificate({ - required String pin, required PivSlot slot, }) => YKFailure.guard( @@ -53,7 +47,6 @@ class DefaultPivProtocol implements PivProtocol { final result = await methodChannel.invokeMethod( 'pivGetCertificate', { - 'pin': pin, 'slot': slot.value, }, ); @@ -68,14 +61,12 @@ class DefaultPivProtocol implements PivProtocol { @override Future calculateSecret({ required PivSlot slot, - required String pin, required String peerPublicKey, }) async { final result = await methodChannel.invokeMethod( 'pivCalculateSecret', { 'slot': slot.value, - 'pin': pin, 'peerPublicKey': Uint8List.fromList( PemCodec(PemLabel.publicKey).decode(peerPublicKey), ), @@ -87,4 +78,33 @@ class DefaultPivProtocol implements PivProtocol { } return result; } + + @override + Future authenticate(PivManagementKey managementKey) async { + final result = await methodChannel.invokeMethod( + 'pivAuthenticate', + { + 'managementKey': managementKey.key, + 'managementKeyType': managementKey.keyType.value, + }, + ); + if (result == null) { + throw YKFailure.other(); + } + return this; + } + + @override + Future verifyPin(String pin) async { + final result = await methodChannel.invokeMethod( + 'pivVerifyPin', + { + 'pin': pin, + }, + ); + if (result == null) { + throw YKFailure.other(); + } + return this; + } } diff --git a/lib/src/infrastructure/yubidart_android.dart b/lib/src/infrastructure/yubidart_android.dart index ce9ba0b..731458e 100644 --- a/lib/src/infrastructure/yubidart_android.dart +++ b/lib/src/infrastructure/yubidart_android.dart @@ -1,10 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:yubidart/src/domain/model/general/device_capabilities.dart'; -import 'package:yubidart/src/domain/protocol/general/protocol.dart'; -import 'package:yubidart/src/domain/protocol/piv/protocol.dart'; +import 'package:yubidart/src/domain/protocol/connection/protocol.dart'; import 'package:yubidart/src/domain/yubidart_platform_interface.dart'; -import 'package:yubidart/src/infrastructure/protocol/piv/default_piv_protocol.dart'; +import 'package:yubidart/src/infrastructure/protocol/connection/default_connection_protocol.dart'; /// An implementation of [YubidartPlatform] for Android. class YubidartAndroid extends YubidartPlatform { @@ -17,17 +15,5 @@ class YubidartAndroid extends YubidartPlatform { } @override - GeneralProtocol get general => DumbGeneralProtocol(); - - @override - PivProtocol get piv => DefaultPivProtocol(); -} - -class DumbGeneralProtocol implements GeneralProtocol { - @override - Future get deviceCapabilities async => - const DeviceCapabilities( - nfc: true, - wired: true, - ); + ConnectionProtocol get connection => DefaultConnectionProtocol(); } diff --git a/lib/src/infrastructure/yubidart_ios.dart b/lib/src/infrastructure/yubidart_ios.dart index b068cc7..4451a2b 100644 --- a/lib/src/infrastructure/yubidart_ios.dart +++ b/lib/src/infrastructure/yubidart_ios.dart @@ -1,8 +1,6 @@ -import 'package:yubidart/src/domain/protocol/general/protocol.dart'; -import 'package:yubidart/src/domain/protocol/piv/protocol.dart'; +import 'package:yubidart/src/domain/protocol/connection/protocol.dart'; import 'package:yubidart/src/domain/yubidart_platform_interface.dart'; -import 'package:yubidart/src/infrastructure/protocol/general/default_general_protocol.dart'; -import 'package:yubidart/src/infrastructure/protocol/piv/default_piv_protocol.dart'; +import 'package:yubidart/src/infrastructure/protocol/connection/default_connection_protocol.dart'; /// An implementation of [YubidartPlatform] that uses method channels. class YubidartIos extends YubidartPlatform { @@ -11,8 +9,5 @@ class YubidartIos extends YubidartPlatform { } @override - GeneralProtocol get general => DefaultGeneralProtocol(); - - @override - PivProtocol get piv => DefaultPivProtocol(); + ConnectionProtocol get connection => DefaultConnectionProtocol(); } diff --git a/lib/yubidart.dart b/lib/yubidart.dart index 94c86cb..e2cd35c 100644 --- a/lib/yubidart.dart +++ b/lib/yubidart.dart @@ -1,9 +1,6 @@ import 'package:yubidart/src/domain/protocol/protocol.dart'; import 'package:yubidart/src/domain/yubidart_platform_interface.dart'; -import 'src/infrastructure/protocol/otp/default_otp_protocol.dart'; -import 'src/infrastructure/protocol/otp/yubicloud_client.dart'; - export 'package:cryptography/dart.dart'; export 'src/domain/model/model.dart'; @@ -12,9 +9,5 @@ export 'src/infrastructure/yubidart_android.dart'; export 'src/infrastructure/yubidart_ios.dart'; class Yubidart { - GeneralProtocol get general => YubidartPlatform.instance.general; - - OTPProtocol get otp => DefaultOTPProtocol(yubicloudClient: YubicloudClient()); - - PivProtocol get piv => YubidartPlatform.instance.piv; + ConnectionProtocol get connection => YubidartPlatform.instance.connection; }