From 94355b42e756cabd2fcc70271e4da9dd60e578b4 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 16 Aug 2023 14:51:25 +0545 Subject: [PATCH] feat: Support DEFAULT profile VC issuance if credential_offer_uri is provided #1793 --- .vscode/launch.json | 8 +--- .../cubit/qr_code_scan_cubit.dart | 4 ++ .../initiate_oidv4vc_credential_issuance.dart | 46 +++++++++++++++++-- lib/splash/bloclisteners/blocklisteners.dart | 1 + lib/splash/view/splash_page.dart | 3 ++ 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 0ae10e8fa..b4e33cecb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,13 +28,7 @@ "request": "launch", "type": "dart", "program": "lib/main_production.dart", - "args": [ - "--flavor", - "production", - "--target", - "lib/main_production.dart", - "--release" - ] + "args": ["--flavor", "production", "--target", "lib/main_production.dart"] } ] } diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 813289df0..1434a43a1 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -17,6 +17,7 @@ import 'package:beacon_flutter/beacon_flutter.dart'; import 'package:bloc/bloc.dart'; import 'package:credential_manifest/credential_manifest.dart'; import 'package:did_kit/did_kit.dart'; +import 'package:dio/dio.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -340,6 +341,7 @@ class QRCodeScanCubit extends Cubit { Future accept({ required Issuer issuer, required QRCodeScanCubit qrCodeScanCubit, + required DioClient dioClient, }) async { emit(state.loading()); final log = getLogger('QRCodeScanCubit - accept'); @@ -366,6 +368,7 @@ class QRCodeScanCubit extends Cubit { didKitProvider: didKitProvider, qrCodeScanCubit: qrCodeScanCubit, secureStorageProvider: getSecureStorage, + dioClient: dioClient, ); return; } @@ -865,6 +868,7 @@ class QRCodeScanCubit extends Cubit { secureStorageProvider: getSecureStorage, credentialTypeOrId: credentialTypeOrId.toString(), isLastCall: i + 1 == credentials.length, + dioClient: DioClient('', Dio()), ); } oidc4vc.resetNonceAndAccessToken(); diff --git a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart index 09f6407d6..4acbfba90 100644 --- a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart +++ b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart @@ -17,6 +17,7 @@ Future initiateOIDC4VCCredentialIssuance({ required DIDKitProvider didKitProvider, required CredentialsCubit credentialsCubit, required SecureStorageProvider secureStorageProvider, + required DioClient dioClient, }) async { final Uri uriFromScannedResponse = Uri.parse(scannedResponse); @@ -25,9 +26,12 @@ Future initiateOIDC4VCCredentialIssuance({ switch (oidc4vcType) { case OIDC4VCType.DEFAULT: case OIDC4VCType.HEDERA: - final credentialOfferJson = jsonDecode( - uriFromScannedResponse.queryParameters['credential_offer'].toString(), + final dynamic credentialOfferJson = await getCredentialOfferJson( + scannedResponse: scannedResponse, + dioClient: dioClient, ); + if (credentialOfferJson == null) throw Exception(); + credentialTypeOrId = credentialOfferJson['credentials']; break; case OIDC4VCType.GAIAX: @@ -54,6 +58,7 @@ Future initiateOIDC4VCCredentialIssuance({ credentialTypeOrId: credentialTypeOrId.toString(), secureStorageProvider: secureStorageProvider, isLastCall: true, + dioClient: dioClient, ); oidc4vc.resetNonceAndAccessToken(); qrCodeScanCubit.goBack(); @@ -69,6 +74,7 @@ Future getAndAddCredential({ required String credentialTypeOrId, required SecureStorageProvider secureStorageProvider, required bool isLastCall, + required DioClient dioClient, }) async { final Uri uriFromScannedResponse = Uri.parse(scannedResponse); @@ -78,9 +84,12 @@ Future getAndAddCredential({ switch (oidc4vcType) { case OIDC4VCType.DEFAULT: case OIDC4VCType.HEDERA: - final credentialOfferJson = jsonDecode( - uriFromScannedResponse.queryParameters['credential_offer'].toString(), + final dynamic credentialOfferJson = await getCredentialOfferJson( + scannedResponse: scannedResponse, + dioClient: dioClient, ); + if (credentialOfferJson == null) throw Exception(); + preAuthorizedCode = credentialOfferJson['grants'] ['urn:ietf:params:oauth:grant-type:pre-authorized_code'] ['pre-authorized_code'] @@ -189,3 +198,32 @@ List getThumbprint(Map privateKey) { return sha256Digest.bytes; } + +Future getCredentialOfferJson({ + required String scannedResponse, + required DioClient dioClient, +}) async { + final Uri uriFromScannedResponse = Uri.parse(scannedResponse); + + final keys = []; + uriFromScannedResponse.queryParameters.forEach((key, value) => keys.add(key)); + + dynamic credentialOfferJson; + + if (keys.contains('credential_offer')) { + credentialOfferJson = jsonDecode( + uriFromScannedResponse.queryParameters['credential_offer'].toString(), + ); + } else if (keys.contains('credential_offer_uri')) { + final url = uriFromScannedResponse.queryParameters['credential_offer_uri'] + .toString(); + final responseUrl = await dioClient.get(url); + final Uri uriFromResponseUrl = Uri.parse(responseUrl as String); + + credentialOfferJson = jsonDecode( + uriFromResponseUrl.queryParameters['credential_offer'].toString(), + ); + } + + return credentialOfferJson; +} diff --git a/lib/splash/bloclisteners/blocklisteners.dart b/lib/splash/bloclisteners/blocklisteners.dart index cd3c015e8..e4c58800a 100644 --- a/lib/splash/bloclisteners/blocklisteners.dart +++ b/lib/splash/bloclisteners/blocklisteners.dart @@ -315,6 +315,7 @@ final qrCodeBlocListener = BlocListener( await context.read().accept( issuer: approvedIssuer, qrCodeScanCubit: context.read(), + dioClient: DioClient('', Dio()), ); } else { context.read().emitError( diff --git a/lib/splash/view/splash_page.dart b/lib/splash/view/splash_page.dart index d8dd2dcc1..03a50b7a1 100644 --- a/lib/splash/view/splash_page.dart +++ b/lib/splash/view/splash_page.dart @@ -12,6 +12,7 @@ import 'package:altme/polygon_id/polygon_id.dart'; import 'package:altme/splash/splash.dart'; import 'package:altme/theme/app_theme/app_theme.dart'; import 'package:did_kit/did_kit.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' as services; @@ -157,6 +158,7 @@ class _SplashViewState extends State { } if (currentOIIDC4VCType != null) { + // ignore: require_trailing_commas await initiateOIDC4VCCredentialIssuance( scannedResponse: uri.toString(), credentialsCubit: context.read(), @@ -164,6 +166,7 @@ class _SplashViewState extends State { didKitProvider: DIDKitProvider(), qrCodeScanCubit: context.read(), secureStorageProvider: secure_storage.getSecureStorage, + dioClient: DioClient('', Dio()), ); } }