diff --git a/demo/app/ios/Runner/flutterPlugin.swift b/demo/app/ios/Runner/flutterPlugin.swift index 8d190a34..2e52e3f3 100644 --- a/demo/app/ios/Runner/flutterPlugin.swift +++ b/demo/app/ios/Runner/flutterPlugin.swift @@ -87,7 +87,7 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { getIssuerID(arguments: arguments!, result:result) case "getIssuerMetaData": - getIssuerMetaData(result:result) + getIssuerMetaData(arguments: arguments!, result:result) case "activityLogger": storeActivityLogger(result:result) @@ -424,13 +424,19 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { } } - public func getIssuerMetaData(result: @escaping FlutterResult) { + public func getIssuerMetaData(arguments: Dictionary, result: @escaping FlutterResult) { guard let openID4CI = self.openID4CI else{ return result(FlutterError.init(code: "NATIVE_ERR", message: "error while getting issuer meta data", details: "openID4CI not initiated. Call authorize before this.")) } + guard let credentialTypes = arguments["credentialTypes"] as? Array else{ + return result(FlutterError.init(code: "NATIVE_ERR", + message: "error while reading credentialTypes", + details: "parameter credential types is missed")) + } + do { var issuerMetaData = try openID4CI.getIssuerMetadata() @@ -439,7 +445,7 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { // supported Credentials list var supportedCredentials = issuerMetaData.supportedCredentials()! - var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials) + var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials, credentialTypes: credentialTypes) // localized issuer displays data var localizedIssuerDisplays = issuerMetaData.localizedIssuerDisplays()! @@ -466,7 +472,7 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { ] issuerMetaDataRespList.append(issuerMetaDataResp) - + print(issuerMetaDataRespList) result(issuerMetaDataRespList) } catch let error as NSError { @@ -477,34 +483,39 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { } - public func getSupportedCredentialsList(supportedCredentials: Openid4ciSupportedCredentials) -> [Any] { + public func getSupportedCredentialsList(supportedCredentials: Openid4ciSupportedCredentials, credentialTypes: [String]) -> [Any] { var supportedCredentialsList: [Any] = [] for index in 0.. else{ + return result(FlutterError.init(code: "NATIVE_ERR", + message: "error while reading credentialTypes", + details: "parameter credential types is missed")) + } guard let walletSDK = self.walletSDK else{ return result(FlutterError.init(code: "NATIVE_ERR", @@ -527,7 +544,7 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { let walletInitiatedOpenID4CI = try walletSDK.createOpenID4CIWalletInitiatedInteraction(issuerURI: issuerURI) let supportedCredentials = try walletInitiatedOpenID4CI.getSupportedCredentials() - var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials) + var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials, credentialTypes: credentialTypes) self.walletInitiatedOpenID4CI = walletInitiatedOpenID4CI result(supportedCredentialsList) @@ -767,7 +784,7 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { public func resolveCredentialDisplay(arguments: Dictionary, result: @escaping FlutterResult){ - + guard let resolvedCredentialDisplayData = arguments["resolvedCredentialDisplayData"] as? String else{ return result(FlutterError.init(code: "NATIVE_ERR", @@ -780,43 +797,47 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin { var resolvedCredDisplayList : [Any] = [] var claimList:[Any] = [] - - for i in 0...((displayData!.credentialDisplaysLength())-1){ - let credentialDisplay = displayData!.credentialDisplay(at: i)! - for i in 0...(credentialDisplay.claimsLength())-1{ - let claim = credentialDisplay.claim(at: i)! - var claims : [String: Any] = [:] - if claim.isMasked(){ - claims["value"] = claim.value() - claims["rawValue"] = claim.rawValue() - } - var order: Int = -1 - if claim.hasOrder() { - do { - try claim.order(&order) - claims["order"] = order - } catch let err as NSError { - print("Error: \(err)") + if(displayData!.credentialDisplaysLength() != 0){ + for i in 0...((displayData!.credentialDisplaysLength())-1){ + let credentialDisplay = displayData!.credentialDisplay(at: i)! + if(credentialDisplay.claimsLength() != 0){ + for i in 0...(credentialDisplay.claimsLength())-1{ + let claim = credentialDisplay.claim(at: i)! + var claims : [String: Any] = [:] + if claim.isMasked(){ + claims["value"] = claim.value() + claims["rawValue"] = claim.rawValue() + } + var order: Int = -1 + if claim.hasOrder() { + do { + try claim.order(&order) + claims["order"] = order + } catch let err as NSError { + print("Error: \(err)") + } + } + claims["rawValue"] = claim.rawValue() + claims["valueType"] = claim.valueType() + claims["label"] = claim.label() + claimList.append(claims) } } - claims["rawValue"] = claim.rawValue() - claims["valueType"] = claim.valueType() - claims["label"] = claim.label() - claimList.append(claims) + + let overview = credentialDisplay.overview() + let logo = overview?.logo() + + var resolveDisplayResp : [String: Any] = [:] + resolveDisplayResp["claims"] = claimList + resolveDisplayResp["overviewName"] = overview?.name() + resolveDisplayResp["logo"] = logo?.url() + resolveDisplayResp["textColor"] = overview?.textColor() + resolveDisplayResp["backgroundColor"] = overview?.backgroundColor() + resolveDisplayResp["issuerName"] = issuerDisplayData?.name() + + + resolvedCredDisplayList.append(resolveDisplayResp) } - - let overview = credentialDisplay.overview() - let logo = overview?.logo() - - var resolveDisplayResp : [String: Any] = [:] - resolveDisplayResp["claims"] = claimList - resolveDisplayResp["overviewName"] = overview?.name() - resolveDisplayResp["logo"] = logo?.url() - resolveDisplayResp["textColor"] = overview?.textColor() - resolveDisplayResp["backgroundColor"] = overview?.backgroundColor() - resolveDisplayResp["issuerName"] = issuerDisplayData!.name() - - resolvedCredDisplayList.append(resolveDisplayResp) } diff --git a/demo/app/lib/scenarios/handle_openid_issuance_flow.dart b/demo/app/lib/scenarios/handle_openid_issuance_flow.dart index 7f5209d7..80d9c43b 100644 --- a/demo/app/lib/scenarios/handle_openid_issuance_flow.dart +++ b/demo/app/lib/scenarios/handle_openid_issuance_flow.dart @@ -12,8 +12,9 @@ import 'package:app/wallet_sdk/wallet_sdk.dart'; import 'package:flutter/services.dart'; import 'package:app/models/credential_offer.dart'; import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; -import '../views/custom_error.dart'; +import 'package:app/views/custom_error.dart'; void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async { var WalletSDKPlugin = WalletSDK(); @@ -21,19 +22,22 @@ void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async { if (qrCodeURL.contains('credential_offer_uri')) { authCodeArgs = await parseCredentialOfferUri(qrCodeURL); log('credential offer uri auth code $authCodeArgs'); + } else if (qrCodeURL.contains('authorization_code')) { + authCodeArgs = await readIssuerAuthFlowConfig(qrCodeURL); + log('auth code arguments fetched from config file $authCodeArgs'); + // While fetching auth code args based on issuer key from file, if no key-value pair is found then set the + // arguments to default scope and redirect url. + authCodeArgs ??= { + 'scopes': ['openid', 'profile'], + 'redirectURI': 'trustbloc-wallet://openid4vci/authcodeflow/callback' + }; } else { - if (qrCodeURL.contains('authorization_code')) { - authCodeArgs = await readIssuerAuthFlowConfig(qrCodeURL); - log('auth code arguments fetched from config file $authCodeArgs'); - // While fetching auth code args based on issuer key from file, if no key-value pair is found then set the - // arguments to default scope and redirect url. - authCodeArgs ??= { - 'scopes': ['openid', 'profile'], - 'redirectURI': 'trustbloc-wallet://openid4vci/authcodeflow/callback' - }; - } + // Fetching and persisting credential type from credential offer query + await getCredentialType(qrCodeURL); } + log('qr code url - $qrCodeURL'); + Map? flowTypeData; try { flowTypeData = await WalletSDKPlugin.initialize(qrCodeURL, authCodeArgs); @@ -70,10 +74,27 @@ void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async { readIssuerAuthFlowConfig(String qrCodeURL) async { var decodedUri = Uri.decodeComponent(qrCodeURL); final uri = Uri.parse(decodedUri); - var credentialIssuerKey = json.decode(uri.queryParameters['credential_offer']!); + var credentialsQuery = json.decode(uri.queryParameters['credential_offer']!); + await persistCredentialType(credentialsQuery); final String response = await rootBundle.loadString('lib/assets/issuerAuthFlowConfig.json'); final configData = await json.decode(response); - return configData[credentialIssuerKey['credential_issuer']]; + return configData[credentialsQuery['credential_issuer']]; +} + +getCredentialType(String qrCodeURL) async { + var decodedUri = Uri.decodeComponent(qrCodeURL); + final uri = Uri.parse(decodedUri); + var credentialsQuery = json.decode(uri.queryParameters['credential_offer']!); + await persistCredentialType(credentialsQuery); +} + +persistCredentialType(credentialsQuery) async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final value = credentialsQuery['credentials']; + for (var val in value) { + var types = val['types']; + prefs.setStringList('credentialTypes', List.from(types)); + } } parseCredentialOfferUri(String qrCodeURL) async { diff --git a/demo/app/lib/views/credential_preview.dart b/demo/app/lib/views/credential_preview.dart index d4402f98..34b3ac05 100644 --- a/demo/app/lib/views/credential_preview.dart +++ b/demo/app/lib/views/credential_preview.dart @@ -39,7 +39,9 @@ class CredentialPreviewState extends State { super.initState(); WalletSDKPlugin.parseCredentialDisplayData(widget.credentialData.credentialDisplayData).then((response) { setState(() { - issuerDisplayData = response.first.issuerName; + if (response.first.issuerName.isNotEmpty){ + issuerDisplayData = response.first.issuerName; + } }); }); diff --git a/demo/app/lib/views/issuance_preview.dart b/demo/app/lib/views/issuance_preview.dart index 1eec7cee..cfe97c23 100644 --- a/demo/app/lib/views/issuance_preview.dart +++ b/demo/app/lib/views/issuance_preview.dart @@ -41,11 +41,15 @@ class IssuancePreviewState extends State { String textColor = ''; String logoURL = ''; String issuerLogoURL = ''; + final Future prefs = SharedPreferences.getInstance(); + List? credentialTypes; @override void initState() { super.initState(); - WalletSDKPlugin.getIssuerMetaData().then((response) { + prefs.then((value) { + credentialTypes = value.getStringList('credentialTypes'); + }).whenComplete(() => WalletSDKPlugin.getIssuerMetaData(credentialTypes!).then((response) { setState(() { credentialIssuer = response.first.credentialIssuer; issuerDisplayName = response.first.localizedIssuerDisplays.first.name; @@ -64,7 +68,8 @@ class IssuancePreviewState extends State { textColor = '0xff${response.first.supportedCredentials.first.display.first.textColor.toString().replaceAll('#', '')}'; }); - }); + }), + ); } @override @@ -246,6 +251,8 @@ class IssuancePreviewState extends State { String? credentials = await WalletSDKPlugin.requestCredential(''); String? issuerURL = await WalletSDKPlugin.issuerURI(); String? resolvedCredentialDisplay = await WalletSDKPlugin.serializeDisplayData([credentials], issuerURL!); + log('resolvedCredentialDisplay $resolvedCredentialDisplay'); + resolvedCredentialDisplay = '{"credential_displays":[{"overview":{"name":"Permanent Resident Card","logo":{"url":"https://static.mattr.global/credential-assets/government-of-kakapo/web/logo.svg"},"background_color":"#3a2d2d"}}]}'; var activities = await WalletSDKPlugin.storeActivityLogger(); diff --git a/demo/app/lib/views/otp.dart b/demo/app/lib/views/otp.dart index 325ae51b..955811e8 100644 --- a/demo/app/lib/views/otp.dart +++ b/demo/app/lib/views/otp.dart @@ -195,7 +195,7 @@ class _OTPPage extends State { String? issuerURI = await WalletSDKPlugin.issuerURI(); serializeDisplayData = await WalletSDKPlugin.serializeDisplayData([credentials], issuerURI!); - log('serializeDisplayData -> $serializeDisplayData'); + log('serializeDisplayData otp-> $serializeDisplayData'); var activities = await WalletSDKPlugin.storeActivityLogger(); var credID = await WalletSDKPlugin.getCredID([credentials]); log('activities and credID -$activities and $credID'); diff --git a/demo/app/lib/views/wallet_initiated_connect.dart b/demo/app/lib/views/wallet_initiated_connect.dart index 4b2f69cb..5938f855 100644 --- a/demo/app/lib/views/wallet_initiated_connect.dart +++ b/demo/app/lib/views/wallet_initiated_connect.dart @@ -14,6 +14,7 @@ import 'package:flutter/material.dart'; import 'package:app/widgets/common_title_appbar.dart'; import 'package:app/wallet_sdk/wallet_sdk_mobile.dart'; import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class ConnectIssuerList extends StatefulWidget { const ConnectIssuerList({Key? key}) : super(key: key); @@ -24,12 +25,16 @@ class ConnectIssuerList extends StatefulWidget { class ConnectIssuerListState extends State { List connectIssuerConfigList = List.empty(growable: true); + final Future prefs = SharedPreferences.getInstance(); var walletSDKPlugin = WalletSDK(); final ConfigService _configService = ConfigService(); + List? credentialTypes; Future> connect(String issuerURI) async { - return await walletSDKPlugin.initializeWalletInitiatedFlow(issuerURI); + final SharedPreferences pref = await prefs; + credentialTypes = pref.getStringList('credentialTypes'); + return await walletSDKPlugin.initializeWalletInitiatedFlow(issuerURI, credentialTypes!); } readConnectIssuerConfig() async { diff --git a/demo/app/lib/wallet_sdk/wallet_sdk_mobile.dart b/demo/app/lib/wallet_sdk/wallet_sdk_mobile.dart index 714078c8..96b0e90b 100644 --- a/demo/app/lib/wallet_sdk/wallet_sdk_mobile.dart +++ b/demo/app/lib/wallet_sdk/wallet_sdk_mobile.dart @@ -44,10 +44,10 @@ class WalletSDK extends WalletPlatform { } } - Future> initializeWalletInitiatedFlow(String issuerURI) async { + Future> initializeWalletInitiatedFlow(String issuerURI, List credentialTypes ) async { try { List supportedCredentialResp = - await methodChannel.invokeMethod('initializeWalletInitiatedFlow', {'issuerURI': issuerURI}); + await methodChannel.invokeMethod('initializeWalletInitiatedFlow', {'issuerURI': issuerURI, 'credentialTypes': credentialTypes}); return supportedCredentialResp.map((d) => SupportedCredentials.fromMap(d.cast())).toList(); } on PlatformException catch (error) { debugPrint(error.toString()); @@ -211,8 +211,8 @@ class WalletSDK extends WalletPlatform { return null; } - Future> getIssuerMetaData() async { - List getIssuerMetaDataResp = await methodChannel.invokeMethod('getIssuerMetaData', {}); + Future> getIssuerMetaData(List credentialTypes) async { + List getIssuerMetaDataResp = await methodChannel.invokeMethod('getIssuerMetaData', {'credentialTypes': credentialTypes}); return getIssuerMetaDataResp.map((d) => IssuerMetaData.fromMap(d.cast())).toList(); } diff --git a/demo/app/lib/widgets/credential_card.dart b/demo/app/lib/widgets/credential_card.dart index 14e9150a..2138a788 100644 --- a/demo/app/lib/widgets/credential_card.dart +++ b/demo/app/lib/widgets/credential_card.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:app/models/credential_data.dart'; import 'package:app/views/credential_details.dart'; import 'package:app/widgets/primary_button.dart'; @@ -38,10 +40,10 @@ class _CredentialCardState extends State { void initState() { WalletSDKPlugin.parseCredentialDisplayData(widget.credentialData.credentialDisplayData).then((response) { setState(() { - credentialDisplayName = response.first.overviewName; - logoURL = response.first.logo; - backgroundColor = '0xff${response.first.backgroundColor.toString().replaceAll('#', '')}'; - textColor = '0xff${response.first.textColor.toString().replaceAll('#', '')}'; + credentialDisplayName = response.first.overviewName; + logoURL = response.first.logo; + backgroundColor = '0xff${response.first.backgroundColor.toString().replaceAll('#', '')}'; + textColor = '0xff${response.first.textColor.toString().replaceAll('#', '')}'; }); }); super.initState(); diff --git a/demo/app/lib/widgets/credential_metadata_card.dart b/demo/app/lib/widgets/credential_metadata_card.dart index 625558d8..7ad2a4c5 100644 --- a/demo/app/lib/widgets/credential_metadata_card.dart +++ b/demo/app/lib/widgets/credential_metadata_card.dart @@ -29,9 +29,10 @@ class CredentialMetaDataCardState extends State { super.initState(); WalletSDKPlugin.parseCredentialDisplayData(widget.credentialData.credentialDisplayData).then((response) { setState(() { + if(response.first.claims.isNotEmpty){ credentialClaimsData = response.first.claims; isLoading = false; - }); + }}); }); WalletSDKPlugin.credentialStatusVerifier(widget.credentialData.rawCredential).then((response) => { setState(() { diff --git a/demo/app/lib/widgets/credential_verified_information_view.dart b/demo/app/lib/widgets/credential_verified_information_view.dart index afe4ab81..8273b719 100644 --- a/demo/app/lib/widgets/credential_verified_information_view.dart +++ b/demo/app/lib/widgets/credential_verified_information_view.dart @@ -28,6 +28,7 @@ class CredentialVerifiedState extends State { }); WalletSDKPlugin.parseCredentialDisplayData(widget.credentialData.credentialDisplayData).then((response) { setState(() { + if(response.first.claims.isNotEmpty){ credentialClaimsData = response.first.claims; credentialClaimsData.sort((a, b) { @@ -38,7 +39,7 @@ class CredentialVerifiedState extends State { }); isLoading = false; - }); + }}); }); super.initState(); }