diff --git a/.metadata b/.metadata index de745e4a0a..882d9f1e43 100644 --- a/.metadata +++ b/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - channel: stable + revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" + channel: "stable" project_type: app @@ -13,26 +13,23 @@ project_type: app migration: platforms: - platform: root - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: android - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: ios - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: linux - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: macos - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: web - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: windows - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 # User provided section diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000000..23854305f5 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +flutter 3.24.0-stable diff --git a/android/app/build.gradle b/android/app/build.gradle index 967d2d4ee2..02eb7e3c5a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,7 +48,7 @@ android { defaultConfig { applicationId "io.ice.app.ion" - minSdkVersion flutter.minSdkVersion + minSdkVersion 28 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000000..5bf7d0357e --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,4 @@ +-if class androidx.credentials.CredentialManager +-keep class androidx.credentials.playservices.** { + *; +} diff --git a/android/settings.gradle b/android/settings.gradle index 7d06449369..a07351b82a 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false + id "org.jetbrains.kotlin.android" version "1.9.10" apply false } include ":app" \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a3cdb21a29..2dc3a4977a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -9,13 +9,12 @@ PODS: - OrderedSet (~> 5.0) - flutter_keyboard_visibility (0.0.1): - Flutter - - image_cropper (0.0.4): - - Flutter - - TOCropViewController (~> 2.6.1) - image_picker_ios (0.0.1): - Flutter - MTBBarcodeScanner (5.0.11) - OrderedSet (5.0.0) + - passkeys_ios (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -32,7 +31,8 @@ PODS: - sqflite (0.0.3): - Flutter - FlutterMacOS - - TOCropViewController (2.6.1) + - ua_client_hints (1.3.1): + - Flutter - url_launcher_ios (0.0.1): - Flutter - video_player_avfoundation (0.0.1): @@ -43,14 +43,15 @@ DEPENDENCIES: - Flutter (from `Flutter`) - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - - image_cropper (from `.symlinks/plugins/image_cropper/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - passkeys_ios (from `.symlinks/plugins/passkeys_ios/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `.symlinks/plugins/sqflite/darwin`) + - ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) @@ -58,7 +59,6 @@ SPEC REPOS: trunk: - MTBBarcodeScanner - OrderedSet - - TOCropViewController EXTERNAL SOURCES: Flutter: @@ -67,10 +67,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" flutter_keyboard_visibility: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" - image_cropper: - :path: ".symlinks/plugins/image_cropper/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + passkeys_ios: + :path: ".symlinks/plugins/passkeys_ios/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: @@ -83,6 +83,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite: :path: ".symlinks/plugins/sqflite/darwin" + ua_client_hints: + :path: ".symlinks/plugins/ua_client_hints/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: @@ -92,17 +94,17 @@ SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_inappwebview_ios: 97215cf7d4677db55df76782dbd2930c5e1c1ea0 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 - image_cropper: a3291c624a953049bc6a02e1f8c8ceb162a24b25 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c + passkeys_ios: fdae8c06e2178a9fcb9261a6cb21fb9a06a81d53 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 + ua_client_hints: 3b617011e47bea4b1ea65647efa12860b7280ad5 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 diff --git a/lib/app/features/auth/providers/auth_provider.dart b/lib/app/features/auth/providers/auth_provider.dart index a2d6955423..a6f1c2986a 100644 --- a/lib/app/features/auth/providers/auth_provider.dart +++ b/lib/app/features/auth/providers/auth_provider.dart @@ -1,6 +1,7 @@ import 'package:ice/app/features/auth/data/models/auth_state.dart'; import 'package:ice/app/features/auth/data/models/auth_token.dart'; import 'package:ice/app/features/core/providers/env_provider.dart'; +import 'package:ion_identity_client/ion_client.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'auth_provider.g.dart'; @@ -24,7 +25,17 @@ class Auth extends _$Auth { Future signIn({required String keyName}) async { try { state = const AuthenticationLoading(); - await Future.delayed(const Duration(seconds: 2)); + + final config = IonClientConfig( + appId: 'ap-dhesg-ct1r8-lu8a7rrodm4an8u', + orgId: 'or-625fn-dfjva-8b993vdrf414bkd8', + origin: 'https://dfns.blockchain.ice.vip', + ); + + final ionClient = IonApiClient.createDefault(config: config); + + final result = await ionClient.auth.registerUser(username: keyName); + state = const Authenticated( authToken: AuthToken(access: 'access', refresh: 'refresh'), ); diff --git a/lib/app/features/auth/views/components/identity_key_name_input/identity_key_name_input.dart b/lib/app/features/auth/views/components/identity_key_name_input/identity_key_name_input.dart index edf2686c48..80fdd175a2 100644 --- a/lib/app/features/auth/views/components/identity_key_name_input/identity_key_name_input.dart +++ b/lib/app/features/auth/views/components/identity_key_name_input/identity_key_name_input.dart @@ -29,6 +29,7 @@ class IdentityKeyNameInput extends HookWidget { Widget build(BuildContext context) { final hideKeyboardAndCallOnce = useHideKeyboardAndCallOnce(); return TextInput( + keyboardType: TextInputType.emailAddress, prefixIcon: TextInputIcons( hasRightDivider: true, icons: [Assets.images.icons.iconIdentitykey.icon()], diff --git a/lib/app/features/core/providers/permissions_provider.dart b/lib/app/features/core/providers/permissions_provider.dart index 7f16a624fe..85e088e2f3 100644 --- a/lib/app/features/core/providers/permissions_provider.dart +++ b/lib/app/features/core/providers/permissions_provider.dart @@ -34,6 +34,7 @@ class Permissions extends _$Permissions { () => contactsPermissionStatus, ); } on MissingPluginException { + } on UnimplementedError { } finally { state = Map.unmodifiable(permissions); } diff --git a/packages/ion_identity_client/.gitignore b/packages/ion_identity_client/.gitignore new file mode 100644 index 0000000000..ac5aa9893e --- /dev/null +++ b/packages/ion_identity_client/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/packages/ion_identity_client/.metadata b/packages/ion_identity_client/.metadata new file mode 100644 index 0000000000..7e6d66adff --- /dev/null +++ b/packages/ion_identity_client/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d" + channel: "stable" + +project_type: package diff --git a/packages/ion_identity_client/CHANGELOG.md b/packages/ion_identity_client/CHANGELOG.md new file mode 100644 index 0000000000..f70b0a0cb7 --- /dev/null +++ b/packages/ion_identity_client/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* This version adds Sign Up with Passkeys. diff --git a/packages/ion_identity_client/LICENSE b/packages/ion_identity_client/LICENSE new file mode 100644 index 0000000000..ba75c69f7f --- /dev/null +++ b/packages/ion_identity_client/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/ion_identity_client/README.md b/packages/ion_identity_client/README.md new file mode 100644 index 0000000000..02fe8ecabc --- /dev/null +++ b/packages/ion_identity_client/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/ion_identity_client/analysis_options.yaml b/packages/ion_identity_client/analysis_options.yaml new file mode 100644 index 0000000000..bf51d72872 --- /dev/null +++ b/packages/ion_identity_client/analysis_options.yaml @@ -0,0 +1,9 @@ +include: package:very_good_analysis/analysis_options.yaml + +analyzer: + errors: + avoid_dynamic_calls: ignore + avoid_positional_boolean_parameters: ignore + lines_longer_than_80_chars: ignore + public_member_api_docs: ignore + unnecessary_library_directive: ignore diff --git a/packages/ion_identity_client/lib/ion_client.dart b/packages/ion_identity_client/lib/ion_client.dart new file mode 100644 index 0000000000..2d47f1ea2e --- /dev/null +++ b/packages/ion_identity_client/lib/ion_client.dart @@ -0,0 +1,5 @@ +library ion_identity_client; + +export 'src/auth/ion_auth.dart'; +export 'src/ion_api_client.dart'; +export 'src/ion_client_config.dart'; diff --git a/packages/ion_identity_client/lib/src/auth/dtos/authentication.dart b/packages/ion_identity_client/lib/src/auth/dtos/authentication.dart new file mode 100644 index 0000000000..e57931abb6 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/authentication.dart @@ -0,0 +1,15 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class Authentication { + Authentication({ + required this.token, + }); + + factory Authentication.fromJson(JsonObject map) { + return Authentication( + token: map['token'] as String, + ); + } + + final String token; +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/credential.dart b/packages/ion_identity_client/lib/src/auth/dtos/credential.dart new file mode 100644 index 0000000000..081e1ec12e --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/credential.dart @@ -0,0 +1,21 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class Credential { + Credential({ + required this.uuid, + required this.kind, + required this.name, + }); + + factory Credential.fromJson(JsonObject map) { + return Credential( + uuid: map['uuid'] as String, + kind: map['kind'] as String, + name: map['name'] as String, + ); + } + + final String uuid; + final String kind; + final String name; +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/dtos.dart b/packages/ion_identity_client/lib/src/auth/dtos/dtos.dart new file mode 100644 index 0000000000..f77ddd82d0 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/dtos.dart @@ -0,0 +1,7 @@ +export 'credential.dart'; +export 'register_complete_request.dart'; +export 'register_complete_response.dart'; +export 'register_init_request.dart'; +export 'signed_challenge.dart'; +export 'user.dart'; +export 'wallet.dart'; diff --git a/packages/ion_identity_client/lib/src/auth/dtos/register_complete_request.dart b/packages/ion_identity_client/lib/src/auth/dtos/register_complete_request.dart new file mode 100644 index 0000000000..05652633a4 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/register_complete_request.dart @@ -0,0 +1,30 @@ +import 'package:ion_identity_client/src/auth/dtos/signed_challenge.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class RegisterCompleteRequest { + RegisterCompleteRequest({ + required this.appId, + required this.signedChallenge, + required this.temporaryAuthenticationToken, + }); + + factory RegisterCompleteRequest.fromJson(JsonObject json) { + return RegisterCompleteRequest( + appId: json['appId'] as String, + signedChallenge: SignedChallenge.fromJson(json['signedChallenge'] as JsonObject), + temporaryAuthenticationToken: json['temporaryAuthenticationToken'] as String, + ); + } + + final String appId; + final SignedChallenge signedChallenge; + final String temporaryAuthenticationToken; + + JsonObject toJson() { + return { + 'appId': appId, + 'signedChallenge': signedChallenge.toJson(), + 'temporaryAuthenticationToken': temporaryAuthenticationToken, + }; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/register_complete_response.dart b/packages/ion_identity_client/lib/src/auth/dtos/register_complete_response.dart new file mode 100644 index 0000000000..9d27a11813 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/register_complete_response.dart @@ -0,0 +1,32 @@ +import 'package:ion_identity_client/src/auth/dtos/authentication.dart'; +import 'package:ion_identity_client/src/auth/dtos/credential.dart'; +import 'package:ion_identity_client/src/auth/dtos/user.dart'; +import 'package:ion_identity_client/src/auth/dtos/wallet.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class RegistrationCompleteResponse { + RegistrationCompleteResponse({ + required this.credential, + required this.user, + required this.authentication, + required this.wallets, + }); + + factory RegistrationCompleteResponse.fromJson(JsonObject json) { + return RegistrationCompleteResponse( + credential: Credential.fromJson(json['credential'] as JsonObject), + user: User.fromJson(json['user'] as JsonObject), + authentication: Authentication.fromJson(json['authentication'] as JsonObject), + wallets: List.from( + (json['wallets'] as List).map( + (x) => Wallet.fromJson(x as JsonObject), + ), + ), + ); + } + + final Credential credential; + final User user; + final Authentication authentication; + final List wallets; +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/register_init_request.dart b/packages/ion_identity_client/lib/src/auth/dtos/register_init_request.dart new file mode 100644 index 0000000000..1a67641123 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/register_init_request.dart @@ -0,0 +1,18 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class RegisterInitRequest { + RegisterInitRequest({ + required this.appId, + required this.username, + }); + + final String appId; + final String username; + + JsonObject toJson() { + return { + 'appId': appId, + 'username': username, + }; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/signed_challenge.dart b/packages/ion_identity_client/lib/src/auth/dtos/signed_challenge.dart new file mode 100644 index 0000000000..d3c007965b --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/signed_challenge.dart @@ -0,0 +1,22 @@ +import 'package:ion_identity_client/src/signer/dtos/fido_2_attestation.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class SignedChallenge { + SignedChallenge({ + required this.firstFactorCredential, + }); + + factory SignedChallenge.fromJson(JsonObject json) { + return SignedChallenge( + firstFactorCredential: Fido2Attestation.fromJson(json['firstFactorCredential'] as JsonObject), + ); + } + + final Fido2Attestation firstFactorCredential; + + JsonObject toJson() { + return { + 'firstFactorCredential': firstFactorCredential.toJson(), + }; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/user.dart b/packages/ion_identity_client/lib/src/auth/dtos/user.dart new file mode 100644 index 0000000000..d26038ea57 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/user.dart @@ -0,0 +1,29 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class User { + User({ + required this.id, + required this.username, + required this.orgId, + }); + + factory User.fromJson(JsonObject map) { + return User( + id: map['id'] as String, + username: map['username'] as String, + orgId: map['orgId'] as String, + ); + } + + final String id; + final String username; + final String orgId; + + JsonObject toJson() { + return { + 'id': id, + 'username': username, + 'orgId': orgId, + }; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/dtos/wallet.dart b/packages/ion_identity_client/lib/src/auth/dtos/wallet.dart new file mode 100644 index 0000000000..74c6c4f24c --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/dtos/wallet.dart @@ -0,0 +1,25 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class Wallet { + const Wallet({ + required this.id, + required this.network, + }); + + factory Wallet.fromJson(JsonObject map) { + return Wallet( + id: map['id'] as String, + network: map['network'] as String, + ); + } + + final String id; + final String network; + + JsonObject toJson() { + return { + 'id': id, + 'network': network, + }; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/ion_auth.dart b/packages/ion_identity_client/lib/src/auth/ion_auth.dart new file mode 100644 index 0000000000..00cb739cc6 --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/ion_auth.dart @@ -0,0 +1,46 @@ +import 'package:ion_identity_client/src/auth/dtos/dtos.dart'; +import 'package:ion_identity_client/src/auth/ion_auth_data_source.dart'; +import 'package:ion_identity_client/src/ion_client_config.dart'; +import 'package:ion_identity_client/src/signer/passkey_signer.dart'; + +class IonAuth { + IonAuth._({ + required this.config, + required this.dataSource, + required this.signer, + }); + + factory IonAuth.createDefault({ + required IonClientConfig config, + required PasskeysSigner signer, + }) { + return IonAuth._( + config: config, + signer: signer, + dataSource: IonAuthDataSource.createDefault( + config: config, + ), + ); + } + + final IonClientConfig config; + final IonAuthDataSource dataSource; + final PasskeysSigner signer; + + Future registerUser({ + required String username, + }) async { + final initResponse = await dataSource.registerInit( + username: username, + ); + + final attestation = await signer.register(initResponse); + + final registerResponse = await dataSource.registerComplete( + attestation: attestation, + temporaryAuthenticationToken: initResponse.temporaryAuthenticationToken, + ); + + return registerResponse; + } +} diff --git a/packages/ion_identity_client/lib/src/auth/ion_auth_data_source.dart b/packages/ion_identity_client/lib/src/auth/ion_auth_data_source.dart new file mode 100644 index 0000000000..200f00842e --- /dev/null +++ b/packages/ion_identity_client/lib/src/auth/ion_auth_data_source.dart @@ -0,0 +1,65 @@ +import 'package:dio/dio.dart'; +import 'package:ion_identity_client/src/auth/dtos/dtos.dart'; +import 'package:ion_identity_client/src/ion_client_config.dart'; +import 'package:ion_identity_client/src/ion_service_locator.dart'; +import 'package:ion_identity_client/src/signer/dtos/dtos.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class IonAuthDataSource { + IonAuthDataSource._({ + required this.config, + required this.dio, + }); + + factory IonAuthDataSource.createDefault({ + required IonClientConfig config, + }) { + final dio = IonServiceLocator.createDio(config: config); + + return IonAuthDataSource._( + config: config, + dio: dio, + ); + } + + static const loginInitPath = '/login'; + static const registerInitPath = '/register/init'; + static const registerCompletePath = '/register/complete'; + + final IonClientConfig config; + final Dio dio; + + Future registerInit({ + required String username, + }) async { + final requestData = RegisterInitRequest( + appId: config.appId, + username: username, + ); + + final response = await dio.post( + registerInitPath, + data: requestData.toJson(), + ); + + return UserRegistrationChallenge.fromJson(response.data ?? {}); + } + + Future registerComplete({ + required Fido2Attestation attestation, + required String temporaryAuthenticationToken, + }) async { + final requestData = RegisterCompleteRequest( + appId: config.appId, + signedChallenge: SignedChallenge(firstFactorCredential: attestation), + temporaryAuthenticationToken: temporaryAuthenticationToken, + ); + + final response = await dio.post( + registerCompletePath, + data: requestData.toJson(), + ); + + return RegistrationCompleteResponse.fromJson(response.data ?? {}); + } +} diff --git a/packages/ion_identity_client/lib/src/ion_api_client.dart b/packages/ion_identity_client/lib/src/ion_api_client.dart new file mode 100644 index 0000000000..9bae0d14db --- /dev/null +++ b/packages/ion_identity_client/lib/src/ion_api_client.dart @@ -0,0 +1,24 @@ +import 'package:ion_identity_client/src/auth/ion_auth.dart'; +import 'package:ion_identity_client/src/ion_client_config.dart'; +import 'package:ion_identity_client/src/signer/passkey_signer.dart'; + +class IonApiClient { + const IonApiClient._({ + required this.auth, + }); + + factory IonApiClient.createDefault({ + required IonClientConfig config, + }) { + final signer = PasskeysSigner(); + + return IonApiClient._( + auth: IonAuth.createDefault( + config: config, + signer: signer, + ), + ); + } + + final IonAuth auth; +} diff --git a/packages/ion_identity_client/lib/src/ion_client_config.dart b/packages/ion_identity_client/lib/src/ion_client_config.dart new file mode 100644 index 0000000000..5b3b871605 --- /dev/null +++ b/packages/ion_identity_client/lib/src/ion_client_config.dart @@ -0,0 +1,11 @@ +class IonClientConfig { + IonClientConfig({ + required this.appId, + required this.orgId, + required this.origin, + }); + + final String appId; + final String orgId; + final String origin; +} diff --git a/packages/ion_identity_client/lib/src/ion_service_locator.dart b/packages/ion_identity_client/lib/src/ion_service_locator.dart new file mode 100644 index 0000000000..60f857b28c --- /dev/null +++ b/packages/ion_identity_client/lib/src/ion_service_locator.dart @@ -0,0 +1,26 @@ +import 'package:dio/dio.dart'; +import 'package:ion_identity_client/src/ion_client_config.dart'; +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; + +class IonServiceLocator { + static Dio createDio({ + required IonClientConfig config, + }) { + final dioOptions = BaseOptions( + baseUrl: config.origin, + headers: { + 'X-DFNS-APPID': config.appId, + }, + ); + final dio = Dio(dioOptions); + + dio.interceptors.add( + PrettyDioLogger( + requestBody: true, + requestHeader: true, + ), + ); + + return dio; + } +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/allow_credentials.dart b/packages/ion_identity_client/lib/src/signer/dtos/allow_credentials.dart new file mode 100644 index 0000000000..dc85ab5da6 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/allow_credentials.dart @@ -0,0 +1,23 @@ +import 'package:ion_identity_client/src/signer/dtos/public_key_credential_descriptor.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class AllowCredentials { + AllowCredentials( + this.webauthn, + this.key, + ); + + factory AllowCredentials.fromJson(JsonObject json) { + return AllowCredentials( + List.from( + json['webauthn'].map(PublicKeyCredentialDescriptor.fromJson) as List, + ), + List.from( + json['key'].map(PublicKeyCredentialDescriptor.fromJson) as List, + ), + ); + } + + final List webauthn; + final List key; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/authenticator_selection_criteria.dart b/packages/ion_identity_client/lib/src/signer/dtos/authenticator_selection_criteria.dart new file mode 100644 index 0000000000..d2cdc21498 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/authenticator_selection_criteria.dart @@ -0,0 +1,24 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class AuthenticatorSelectionCriteria { + AuthenticatorSelectionCriteria( + this.authenticatorAttachment, + this.residentKey, + this.requireResidentKey, + this.userVerification, + ); + + factory AuthenticatorSelectionCriteria.fromJson(JsonObject json) { + return AuthenticatorSelectionCriteria( + json['authenticatorAttachment'] as String?, + json['residentKey'] as String, + json['requireResidentKey'] as bool, + json['userVerification'] as String, + ); + } + + final String? authenticatorAttachment; + final String residentKey; + final bool requireResidentKey; + final String userVerification; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/dtos.dart b/packages/ion_identity_client/lib/src/signer/dtos/dtos.dart new file mode 100644 index 0000000000..6a14788889 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/dtos.dart @@ -0,0 +1,14 @@ +export 'allow_credentials.dart'; +export 'authenticator_selection_criteria.dart'; +export 'fido_2_assertion.dart'; +export 'fido_2_assertion_data.dart'; +export 'fido_2_attestation.dart'; +export 'fido_2_attestation_data.dart'; +export 'public_key_credential_descriptor.dart'; +export 'public_key_credential_parameters.dart'; +export 'relying_party.dart'; +export 'supported_credential_kinds.dart'; +export 'supported_credential_kinds_2.dart'; +export 'user_action_challenge.dart'; +export 'user_information.dart'; +export 'user_registration_challenge.dart'; diff --git a/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion.dart b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion.dart new file mode 100644 index 0000000000..e2bdf513c9 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion.dart @@ -0,0 +1,24 @@ +import 'package:ion_identity_client/src/signer/dtos/fido_2_assertion_data.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class Fido2Assertion { + Fido2Assertion( + this.kind, + this.credentialAssertion, + ); + + factory Fido2Assertion.fromJson(JsonObject json) { + return Fido2Assertion( + json['kind'] as String, + Fido2AssertionData.fromJson(json['credentialAssertion'] as JsonObject), + ); + } + + final String kind; + final Fido2AssertionData credentialAssertion; + + JsonObject toJson() => { + 'kind': kind, + 'credentialAssertion': credentialAssertion.toJson(), + }; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion_data.dart b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion_data.dart new file mode 100644 index 0000000000..067184da6d --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_assertion_data.dart @@ -0,0 +1,35 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class Fido2AssertionData { + Fido2AssertionData( + this.clientData, + this.credId, + this.signature, + this.authenticatorData, + this.userHandle, + ); + + factory Fido2AssertionData.fromJson(JsonObject json) { + return Fido2AssertionData( + json['clientData'] as String, + json['credId'] as String, + json['signature'] as String, + json['authenticatorData'] as String, + json['userHandle'] as String, + ); + } + + final String clientData; + final String credId; + final String signature; + final String authenticatorData; + final String? userHandle; + + JsonObject toJson() => { + 'clientData': clientData, + 'credId': credId, + 'signature': signature, + 'authenticatorData': authenticatorData, + 'userHandle': userHandle, + }; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation.dart b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation.dart new file mode 100644 index 0000000000..f1d2ee2296 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation.dart @@ -0,0 +1,24 @@ +import 'package:ion_identity_client/src/signer/dtos/fido_2_attestation_data.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class Fido2Attestation { + Fido2Attestation( + this.credentialInfo, + this.credentialKind, + ); + + factory Fido2Attestation.fromJson(JsonObject json) { + return Fido2Attestation( + Fido2AttestationData.fromJson(json['credentialInfo'] as JsonObject), + json['credentialKind'] as String, + ); + } + + final Fido2AttestationData credentialInfo; + final String credentialKind; + + JsonObject toJson() => { + 'credentialInfo': credentialInfo.toJson(), + 'credentialKind': credentialKind, + }; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation_data.dart b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation_data.dart new file mode 100644 index 0000000000..dcc0d8d3e8 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/fido_2_attestation_data.dart @@ -0,0 +1,27 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class Fido2AttestationData { + Fido2AttestationData( + this.attestationData, + this.clientData, + this.credId, + ); + + factory Fido2AttestationData.fromJson(JsonObject json) { + return Fido2AttestationData( + json['attestationData'] as String, + json['clientData'] as String, + json['credId'] as String, + ); + } + + final String attestationData; + final String clientData; + final String credId; + + JsonObject toJson() => { + 'attestationData': attestationData, + 'clientData': clientData, + 'credId': credId, + }; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_descriptor.dart b/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_descriptor.dart new file mode 100644 index 0000000000..2d187513c6 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_descriptor.dart @@ -0,0 +1,16 @@ +class PublicKeyCredentialDescriptor { + PublicKeyCredentialDescriptor( + this.type, + this.id, + ); + + factory PublicKeyCredentialDescriptor.fromJson(dynamic json) { + return PublicKeyCredentialDescriptor( + json['type'] as String, + json['id'] as String, + ); + } + + final String type; + final String id; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_parameters.dart b/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_parameters.dart new file mode 100644 index 0000000000..5ab8950fd8 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/public_key_credential_parameters.dart @@ -0,0 +1,18 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class PublicKeyCredentialParameters { + PublicKeyCredentialParameters( + this.type, + this.alg, + ); + + factory PublicKeyCredentialParameters.fromJson(JsonObject json) { + return PublicKeyCredentialParameters( + json['type'] as String, + json['alg'] as int, + ); + } + + final String type; + final int alg; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/relying_party.dart b/packages/ion_identity_client/lib/src/signer/dtos/relying_party.dart new file mode 100644 index 0000000000..231e7192a4 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/relying_party.dart @@ -0,0 +1,15 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class RelyingParty { + RelyingParty(this.id, this.name); + + factory RelyingParty.fromJson(JsonObject json) { + return RelyingParty( + json['id'] as String, + json['name'] as String, + ); + } + + final String id; + final String name; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds.dart b/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds.dart new file mode 100644 index 0000000000..487fd65cd6 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds.dart @@ -0,0 +1,18 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class SupportedCredentialKinds { + SupportedCredentialKinds( + this.firstFactor, + this.secondFactor, + ); + + factory SupportedCredentialKinds.fromJson(JsonObject json) { + return SupportedCredentialKinds( + List.from(json['firstFactor'] as List), + List.from(json['secondFactor'] as List), + ); + } + + final List firstFactor; + final List secondFactor; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds_2.dart b/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds_2.dart new file mode 100644 index 0000000000..ab2d04d0e4 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/supported_credential_kinds_2.dart @@ -0,0 +1,21 @@ +import 'package:ion_identity_client/src/utils/types.dart'; + +class SupportedCredentialKinds2 { + SupportedCredentialKinds2( + this.kind, + this.factor, + this.requiresSecondFactor, + ); + + factory SupportedCredentialKinds2.fromJson(JsonObject json) { + return SupportedCredentialKinds2( + json['kind'] as String, + json['factor'] as String, + json['requiresSecondFactor'] as bool, + ); + } + + final String kind; + final String factor; + final bool requiresSecondFactor; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/user_action_challenge.dart b/packages/ion_identity_client/lib/src/signer/dtos/user_action_challenge.dart new file mode 100644 index 0000000000..3691d0de75 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/user_action_challenge.dart @@ -0,0 +1,41 @@ +import 'package:ion_identity_client/src/signer/dtos/allow_credentials.dart'; +import 'package:ion_identity_client/src/signer/dtos/relying_party.dart'; +import 'package:ion_identity_client/src/signer/dtos/supported_credential_kinds_2.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class UserActionChallenge { + UserActionChallenge( + this.attestation, + this.userVerification, + this.externalAuthenticationUrl, + this.challenge, + this.challengeIdentifier, + this.rp, + this.supportedCredentialKinds, + this.allowCredentials, + ); + + factory UserActionChallenge.fromJson(JsonObject json) { + return UserActionChallenge( + json['attestation'] as String, + json['userVerification'] as String, + json['externalAuthenticationUrl'] as String, + json['challenge'] as String, + json['challengeIdentifier'] as String, + RelyingParty.fromJson(json['rp'] as JsonObject), + List.from( + json['supportedCredentialKinds'].map(SupportedCredentialKinds2.fromJson) as List, + ), + AllowCredentials.fromJson(json['allowCredentials'] as JsonObject), + ); + } + + final String attestation; + final String userVerification; + final String externalAuthenticationUrl; + final String challenge; + final String challengeIdentifier; + final RelyingParty rp; + final List supportedCredentialKinds; + final AllowCredentials allowCredentials; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/user_information.dart b/packages/ion_identity_client/lib/src/signer/dtos/user_information.dart new file mode 100644 index 0000000000..b153202b41 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/user_information.dart @@ -0,0 +1,15 @@ +class UserInformation { + UserInformation(this.id, this.displayName, this.name); + + factory UserInformation.fromJson(dynamic json) { + return UserInformation( + json['id'] as String, + json['displayName'] as String, + json['name'] as String, + ); + } + + final String id; + final String displayName; + final String name; +} diff --git a/packages/ion_identity_client/lib/src/signer/dtos/user_registration_challenge.dart b/packages/ion_identity_client/lib/src/signer/dtos/user_registration_challenge.dart new file mode 100644 index 0000000000..c60d72a382 --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/dtos/user_registration_challenge.dart @@ -0,0 +1,54 @@ +import 'package:ion_identity_client/src/signer/dtos/authenticator_selection_criteria.dart'; +import 'package:ion_identity_client/src/signer/dtos/public_key_credential_descriptor.dart'; +import 'package:ion_identity_client/src/signer/dtos/public_key_credential_parameters.dart'; +import 'package:ion_identity_client/src/signer/dtos/relying_party.dart'; +import 'package:ion_identity_client/src/signer/dtos/supported_credential_kinds.dart'; +import 'package:ion_identity_client/src/signer/dtos/user_information.dart'; +import 'package:ion_identity_client/src/utils/types.dart'; + +class UserRegistrationChallenge { + UserRegistrationChallenge( + this.temporaryAuthenticationToken, + this.rp, + this.user, + this.supportedCredentialKinds, + this.otpUrl, + this.challenge, + this.authenticatorSelection, + this.attestation, + this.pubKeyCredParams, + this.excludeCredentials, + ); + + factory UserRegistrationChallenge.fromJson(JsonObject json) { + return UserRegistrationChallenge( + json['temporaryAuthenticationToken'] as String, + RelyingParty.fromJson(json['rp'] as JsonObject), + UserInformation.fromJson(json['user']), + SupportedCredentialKinds.fromJson(json['supportedCredentialKinds'] as JsonObject), + json['otpUrl'] as String, + json['challenge'] as String, + AuthenticatorSelectionCriteria.fromJson(json['authenticatorSelection'] as JsonObject), + json['attestation'] as String, + List.from( + (json['pubKeyCredParams'] as Iterable) + .map((e) => PublicKeyCredentialParameters.fromJson(e as JsonObject)), + ), + List.from( + (json['excludeCredentials'] as Iterable) + .map((e) => PublicKeyCredentialDescriptor.fromJson(e as JsonObject)), + ), + ); + } + + final String temporaryAuthenticationToken; + final RelyingParty rp; + final UserInformation user; + final SupportedCredentialKinds supportedCredentialKinds; + final String otpUrl; + final String challenge; + final AuthenticatorSelectionCriteria authenticatorSelection; + final String attestation; + final List pubKeyCredParams; + final List excludeCredentials; +} diff --git a/packages/ion_identity_client/lib/src/signer/passkey_signer.dart b/packages/ion_identity_client/lib/src/signer/passkey_signer.dart new file mode 100644 index 0000000000..000db505ff --- /dev/null +++ b/packages/ion_identity_client/lib/src/signer/passkey_signer.dart @@ -0,0 +1,108 @@ +import 'dart:convert'; + +import 'package:ion_identity_client/src/signer/dtos/fido_2_assertion.dart'; +import 'package:ion_identity_client/src/signer/dtos/fido_2_assertion_data.dart'; +import 'package:ion_identity_client/src/signer/dtos/fido_2_attestation.dart'; +import 'package:ion_identity_client/src/signer/dtos/fido_2_attestation_data.dart'; +import 'package:ion_identity_client/src/signer/dtos/user_action_challenge.dart'; +import 'package:ion_identity_client/src/signer/dtos/user_registration_challenge.dart'; +import 'package:passkeys/authenticator.dart'; +import 'package:passkeys/types.dart'; + +const int defaultWaitTimeout = 60000; + +class PasskeysOptions { + PasskeysOptions(this.timeout); + + final int? timeout; +} + +class PasskeysSigner { + PasskeysSigner([this.options]); + + PasskeysOptions? options; + + Future register(UserRegistrationChallenge challenge) async { + final registerResponse = await PasskeyAuthenticator().register( + RegisterRequestType( + challenge: challenge.challenge, + relyingParty: RelyingPartyType( + name: challenge.rp.name, + id: challenge.rp.id, + ), + user: UserType( + displayName: challenge.user.displayName, + name: challenge.user.name, + id: base64UrlEncode(utf8.encode(challenge.user.id)), + ), + authSelectionType: AuthenticatorSelectionType( + authenticatorAttachment: + challenge.authenticatorSelection.authenticatorAttachment ?? 'platform', + requireResidentKey: challenge.authenticatorSelection.requireResidentKey, + residentKey: challenge.authenticatorSelection.residentKey, + userVerification: challenge.authenticatorSelection.userVerification, + ), + pubKeyCredParams: List.from( + challenge.pubKeyCredParams.map( + (e) => PubKeyCredParamType( + type: e.type, + alg: e.alg, + ), + ), + ), + timeout: options?.timeout ?? defaultWaitTimeout, + attestation: challenge.attestation, + excludeCredentials: List.from( + challenge.excludeCredentials.map( + (e) => CredentialType( + type: e.type, + id: e.id, + transports: [], + ), + ), + ), + ), + ); + + return Fido2Attestation( + Fido2AttestationData( + registerResponse.attestationObject, + registerResponse.clientDataJSON, + registerResponse.rawId, + ), + 'Fido2', + ); + } + + Future sign(UserActionChallenge challenge) async { + final fido2Assertion = await PasskeyAuthenticator().authenticate( + AuthenticateRequestType( + relyingPartyId: challenge.rp.id, + challenge: challenge.challenge, + timeout: options?.timeout ?? defaultWaitTimeout, + userVerification: challenge.userVerification, + allowCredentials: List.from( + challenge.allowCredentials.webauthn.map( + (e) => CredentialType( + type: e.type, + id: e.id, + transports: [], + ), + ), + ), + mediation: MediationType.Required, + ), + ); + + return Fido2Assertion( + 'Fido2', + Fido2AssertionData( + fido2Assertion.clientDataJSON, + fido2Assertion.rawId, + fido2Assertion.signature, + fido2Assertion.authenticatorData, + fido2Assertion.userHandle, + ), + ); + } +} diff --git a/packages/ion_identity_client/lib/src/utils/types.dart b/packages/ion_identity_client/lib/src/utils/types.dart new file mode 100644 index 0000000000..2f4306b95d --- /dev/null +++ b/packages/ion_identity_client/lib/src/utils/types.dart @@ -0,0 +1 @@ +typedef JsonObject = Map; diff --git a/packages/ion_identity_client/pubspec.yaml b/packages/ion_identity_client/pubspec.yaml new file mode 100644 index 0000000000..825a1e88ab --- /dev/null +++ b/packages/ion_identity_client/pubspec.yaml @@ -0,0 +1,20 @@ +name: ion_identity_client +version: 0.0.1 + +environment: + sdk: '>=3.3.4 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + dio: 5.5.0+1 + flutter: + sdk: flutter + passkeys: ^2.0.9 + pretty_dio_logger: ^1.4.0 + +dev_dependencies: + flutter_test: + sdk: flutter + very_good_analysis: ^6.0.0 + +flutter: diff --git a/pubspec.lock b/pubspec.lock index 5e6e961cdb..f81b1da344 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -246,6 +246,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + corbado_frontend_api_client: + dependency: transitive + description: + name: corbado_frontend_api_client + sha256: "7040edd0b73ef023ab3fb82da9d284d1f53ba31037d7c227747b527d168855a3" + url: "https://pub.dev" + source: hosted + version: "1.1.1" cross_file: dependency: transitive description: @@ -326,6 +334,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + dio: + dependency: transitive + description: + name: dio + sha256: e17f6b3097b8c51b72c74c9f071a605c47bcc8893839bd66732457a5ebe73714 + url: "https://pub.dev" + source: hosted + version: "5.5.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac" + url: "https://pub.dev" + source: hosted + version: "1.0.1" dotted_border: dependency: "direct main" description: @@ -882,14 +906,21 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + ion_identity_client: + dependency: "direct main" + description: + path: "packages/ion_identity_client" + relative: true + source: path + version: "0.0.1" js: - dependency: transitive + dependency: "direct overridden" description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" json_annotation: dependency: "direct main" description: @@ -1027,6 +1058,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + openapi_generator_annotations: + dependency: transitive + description: + name: openapi_generator_annotations + sha256: "86d924de3037a4a82e8a8d3b60c4120eced3df9e6b52a7d17cdec12ff4299ac5" + url: "https://pub.dev" + source: hosted + version: "5.0.2" package_config: dependency: transitive description: @@ -1035,6 +1074,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + passkeys: + dependency: transitive + description: + name: passkeys + sha256: f7858feeb9fcaa3b206e8eb0ee6da4bf6ad90c9a35a30f7df0cd1cb78227a96f + url: "https://pub.dev" + source: hosted + version: "2.0.9" + passkeys_android: + dependency: transitive + description: + name: passkeys_android + sha256: "9dc0b84dad03329ff2f3be18bedecf1b8de9309c8e9cda6ef821dc88556a126d" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + passkeys_ios: + dependency: transitive + description: + name: passkeys_ios + sha256: "411b10c3cd159c9601426d47b2dc5aa4dd1e34ef69deefaac01ff81712ea6064" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + passkeys_platform_interface: + dependency: transitive + description: + name: passkeys_platform_interface + sha256: a1f1f5c637049f68350cf43323df9689be2e86fe5822a6e098362e7f6168351e + url: "https://pub.dev" + source: hosted + version: "2.0.1" + passkeys_web: + dependency: transitive + description: + name: passkeys_web + sha256: "04b306c484f1a7d30720785563c160b46cf9232a708ce65286863f91dd78b19d" + url: "https://pub.dev" + source: hosted + version: "2.0.2" path: dependency: transitive description: @@ -1195,6 +1274,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + pretty_dio_logger: + dependency: transitive + description: + name: pretty_dio_logger + sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407" + url: "https://pub.dev" + source: hosted + version: "1.4.0" pub_semver: dependency: transitive description: @@ -1552,6 +1639,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + ua_client_hints: + dependency: transitive + description: + name: ua_client_hints + sha256: ee3da4e4b6ed211fe54deaa19832dd25613f11fc2951912d4e62a093da03fbbb + url: "https://pub.dev" + source: hosted + version: "1.3.1" url_launcher: dependency: "direct main" description: @@ -1580,10 +1675,10 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.0" url_launcher_macos: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a25b24b4ea..28d680cb73 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,6 +49,8 @@ dependencies: video_player: ^2.9.1 widgetbook: ^3.7.1 widgetbook_annotation: ^3.1.0 + ion_identity_client: + path: packages/ion_identity_client dev_dependencies: build_runner: ^2.4.8 diff --git a/web/index.html b/web/index.html index 353862cbb5..7f9380b2b4 100644 --- a/web/index.html +++ b/web/index.html @@ -32,28 +32,9 @@ ice - - - + - +