Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): Implement issuance preview screen ios #533

Merged
merged 1 commit into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ SPEC CHECKSUMS:
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
integration_test: 13825b8a9334a850581300559b8839134b124670
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
safe_device: 4539eb6bdbeb4b61a763a51c4e73e6b37dea4e3d
Expand Down
7 changes: 7 additions & 0 deletions demo/app/ios/Runner/OpenID4CI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,11 @@ public class OpenID4CI {
func getAuthorizationCodeGrantParams() throws -> Openid4ciAuthorizationCodeGrantParams {
return try initiatedInteraction.authorizationCodeGrantParams()
}

// Not doing locale handling or text color handling etc.
func getIssuerMetadata() throws -> Openid4ciIssuerMetadata {
return try initiatedInteraction.issuerMetadata()
}


}
101 changes: 87 additions & 14 deletions demo/app/ios/Runner/flutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin {
case "getIssuerID":
getIssuerID(arguments: arguments!, result:result)

case "getIssuerMetaData":
getIssuerMetaData(result:result)

case "activityLogger":
storeActivityLogger(result:result)

Expand Down Expand Up @@ -404,6 +407,88 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin {
}
}

public func getIssuerMetaData(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."))
}

do {

var issuerMetaData = try openID4CI.getIssuerMetadata()
// creddential issuer
var credIssuer = issuerMetaData.credentialIssuer()

// supported Credentials list
var supportedCredentials = issuerMetaData.supportedCredentials()!
var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials)

// localized issuer displays data
var localizedIssuerDisplays = issuerMetaData.localizedIssuerDisplays()!
var localizedIssuerDisplayList :[Any] = []
for index in 0..<localizedIssuerDisplays.length() {
let localizedIssuerDisplay :[String:Any] = [
"name": localizedIssuerDisplays.atIndex(index)!.name(),
"locale": localizedIssuerDisplays.atIndex(index)!.locale(),
]

localizedIssuerDisplayList.append(localizedIssuerDisplay)
}


var issuerMetaDataRespList: [Any] = []
let issuerMetaDataResp:[String:Any] = [
"credentialIssuer": credIssuer,
"supportedCredentials" : supportedCredentialsList,
"localizedIssuerDisplays":localizedIssuerDisplayList
]

issuerMetaDataRespList.append(issuerMetaDataResp)

result(issuerMetaDataRespList)

} catch {
result(FlutterError.init(code: "NATIVE_ERR",
message: "error while getting issuer meta data",
details: error))
}

}

public func getSupportedCredentialsList(supportedCredentials: Openid4ciSupportedCredentials) -> [Any] {
var supportedCredentialsList: [Any] = []
for index in 0..<supportedCredentials.length() {
var typeStrArray = [String]()
for i in 0..<(supportedCredentials.atIndex(index)!.types()?.length())!{
let type1 = supportedCredentials.atIndex(index)!.types()?.atIndex(i)
typeStrArray.append(type1!)
}

var localizedCredentialsDisplayRespList: [Any] = []
for i in 0..<(supportedCredentials.atIndex(index)!.localizedDisplays()?.length())!{
let localizedCredentialsDisplayResp :[String:Any] = [
"name": supportedCredentials.atIndex(index)!.localizedDisplays()!.atIndex(i)!.name(),
"locale": supportedCredentials.atIndex(index)!.localizedDisplays()!.atIndex(i)!.locale(),
"logo": supportedCredentials.atIndex(index)!.localizedDisplays()!.atIndex(i)!.logo()!.url(),
"textColor": supportedCredentials.atIndex(index)!.localizedDisplays()!.atIndex(i)!.textColor(),
"backgroundColor": supportedCredentials.atIndex(index)!.localizedDisplays()!.atIndex(i)!.backgroundColor()
]
localizedCredentialsDisplayRespList.append(localizedCredentialsDisplayResp)
}

let supportedCredentialResp:[String:Any] = [
"format": supportedCredentials.atIndex(index)!.format(),
"types": typeStrArray,
"display": localizedCredentialsDisplayRespList
]

supportedCredentialsList.append(supportedCredentialResp)
}

return supportedCredentialsList
}

public func initializeWalletInitiatedFlow(arguments: Dictionary<String, Any>, result: @escaping FlutterResult){
guard let issuerURI = arguments["issuerURI"] as? String else {
return result(FlutterError.init(code: "NATIVE_ERR",
Expand All @@ -422,20 +507,8 @@ public class SwiftWalletSDKPlugin: NSObject, FlutterPlugin {
let walletInitiatedOpenID4CI = try walletSDK.createOpenID4CIWalletIntiatedInteraction(issuerURI: issuerURI)
let supportedCredentials = try walletInitiatedOpenID4CI.getSupportedCredentials()

var supportedCredentialsList: [Any] = []
for index in 0..<supportedCredentials.length() {
var typeStrArray = [String]()
for i in 0..<(supportedCredentials.atIndex(index)!.types()?.length())!{
let type1 = supportedCredentials.atIndex(index)!.types()?.atIndex(i)
typeStrArray.append(type1!)
}

let supportedCredentialResp:[String:Any] = [
"format": supportedCredentials.atIndex(index)!.format(),
"types": typeStrArray
]
supportedCredentialsList.append(supportedCredentialResp)
}
var supportedCredentialsList = getSupportedCredentialsList(supportedCredentials: supportedCredentials)

self.walletInitiatedOpenID4CI = walletInitiatedOpenID4CI
result(supportedCredentialsList)

Expand Down
88 changes: 16 additions & 72 deletions demo/app/lib/scenarios/handle_openid_issuance_flow.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ SPDX-License-Identifier: Apache-2.0

import 'dart:convert';
import 'dart:developer';
import 'package:app/views/issuance_preview.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:app/wallet_sdk/wallet_sdk.dart';
import 'package:app/models/activity_data_object.dart';
import 'package:app/models/credential_data.dart';
import 'package:app/services/storage_service.dart';
import 'package:app/views/credential_preview.dart';
import 'package:app/views/otp.dart';
import 'package:app/views/handle_redirect_uri.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:app/models/credential_offer.dart';
Expand All @@ -25,22 +21,19 @@ void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async {
final StorageService storageService = StorageService();
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
var authCodeArgs;
if (qrCodeURL.contains("credential_offer_uri")){
if (qrCodeURL.contains("credential_offer_uri")) {
authCodeArgs = await parseCredentialOfferUri(qrCodeURL);
log("credential offer uri auth code ${authCodeArgs}");
} else {
if (qrCodeURL.contains("authorization_code")){
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"
};
"scopes": ["openid", "profile"],
"redirectURI": "trustbloc-wallet://openid4vci/authcodeflow/callback"
};
}
}

Expand All @@ -50,21 +43,21 @@ void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async {
var authorizeResultPinRequired = responseJson["pinRequired"];
log("pin required flow - $authorizeResultPinRequired");
if (authorizeResultPinRequired == true) {
navigateToOTPScreen(context);
navigateToIssuancePreviewScreen(context, authorizeResultPinRequired);
return;
} else if (responseJson["authorizationURLLink"] != '') {
// initiate authCode Flow
log("initiating authCode Flow- ${responseJson["authorizationURLLink"]}");
Uri uri = Uri.parse(responseJson["authorizationURLLink"]);
navigateToAuthFlow(context, uri);
navigateToIssuancePreviewScreenAuthFlow(context, uri);
return;
} else {
navigateToWithoutPinFlow(context);
navigateToIssuancePreviewScreen(context, authorizeResultPinRequired);
return;
}
}

readIssuerAuthFlowConfig(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"]!);
Expand All @@ -76,8 +69,7 @@ void handleOpenIDIssuanceFlow(BuildContext context, String qrCodeURL) async {
parseCredentialOfferUri(String qrCodeURL) async {
var decodedUri = Uri.decodeComponent(qrCodeURL);
final uri = Uri.parse(decodedUri);
final response = await http
.get(Uri.parse(uri.queryParameters['credential_offer_uri']!));
final response = await http.get(Uri.parse(uri.queryParameters['credential_offer_uri']!));
if (response.statusCode == 200) {
final String configResp = await rootBundle.loadString('lib/assets/issuerAuthFlowConfig.json');
final configData = await json.decode(configResp);
Expand All @@ -88,59 +80,11 @@ parseCredentialOfferUri(String qrCodeURL) async {
}
}

void navigateToWithoutPinFlow(BuildContext context) async{
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
var WalletSDKPlugin = WalletSDK();
final StorageService storageService = StorageService();
final SharedPreferences pref = await prefs;

var didType = pref.getString('didType');
var keyType = pref.getString('keyType');
// choosing default if no selection is made
didType = didType ?? "ion";
keyType = keyType ?? "ED25519";

var didResolution = await WalletSDKPlugin.createDID(didType, keyType);
var didDocEncoded = json.encode(didResolution);
Map<String, dynamic> responseJson = json.decode(didDocEncoded);

var didID = responseJson["did"];
var didDoc = responseJson["didDoc"];
log("created didID :$didID");
pref.setString('userDID',didID);
pref.setString('userDIDDoc',didDoc);

String? credentials = await WalletSDKPlugin.requestCredential('');
String? issuerURL = await WalletSDKPlugin.issuerURI();
String? resolvedCredentialDisplay = await WalletSDKPlugin.serializeDisplayData([credentials],issuerURL!);

var activities = await WalletSDKPlugin.storeActivityLogger();

var credID = await WalletSDKPlugin.getCredID([credentials]);

log("activities and credID handle open id -$activities and $credID");
storageService.addActivities(ActivityDataObj(credID!, activities));

navigateToCredPreviewScreen(context, credentials, issuerURL, resolvedCredentialDisplay!, didID, credID);
void navigateToIssuancePreviewScreen(BuildContext context, bool? authorizeResultPinRequired) async {
Navigator.push(context,
MaterialPageRoute(builder: (context) => IssuancePreview(authorizeResultPinRequired: authorizeResultPinRequired)));
}

void navigateToOTPScreen(BuildContext context) async {
Navigator.push(context, MaterialPageRoute(builder: (context) => const OTP()));
void navigateToIssuancePreviewScreenAuthFlow(BuildContext context, Uri uri) async {
Navigator.push(context, MaterialPageRoute(builder: (context) => IssuancePreview(uri: uri)));
}

navigateToCredPreviewScreen(
BuildContext context, String credentialResp, String issuerURL, String resolvedCredentialDisplay, String didID, String credID) async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CredentialPreview(credentialData: CredentialData(rawCredential: credentialResp, issuerURL: issuerURL, credentialDisplayData: resolvedCredentialDisplay, credentialDID: didID, credID: credID)),));
}


void navigateToAuthFlow(BuildContext context, Uri uri) async {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => HandleRedirectUri(uri, "issuer-initiated-flow", "")
));
}
Loading