Skip to content

Commit

Permalink
Merge pull request #29 from moratori/feature-multi-presentation
Browse files Browse the repository at this point in the history
Feature multi presentation
  • Loading branch information
ryosuke-wakaba authored Oct 2, 2024
2 parents 352857e + 15b6937 commit 0b6f704
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 116 deletions.
4 changes: 0 additions & 4 deletions tw2023_wallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
8B80569C2B5F7815009A87C8 /* SharingCredentialArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B80569B2B5F7815009A87C8 /* SharingCredentialArgs.swift */; };
8B80569D2B5F7815009A87C8 /* SharingCredentialArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B80569B2B5F7815009A87C8 /* SharingCredentialArgs.swift */; };
8B80569F2B60E2FB009A87C8 /* PreferencesDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B80569E2B60E2FB009A87C8 /* PreferencesDataStore.swift */; };
8B8056A12B6381BD009A87C8 /* CredentialSharingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B8056A02B6381BD009A87C8 /* CredentialSharingModel.swift */; };
8B81E29D2B33CC4000ED3B4E /* tw2023_walletApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B81E29C2B33CC4000ED3B4E /* tw2023_walletApp.swift */; };
8B81E29F2B33CC4000ED3B4E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B81E29E2B33CC4000ED3B4E /* ContentView.swift */; };
8B81E2A12B33CC4200ED3B4E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B81E2A02B33CC4200ED3B4E /* Assets.xcassets */; };
Expand Down Expand Up @@ -340,7 +339,6 @@
8B774A532B7B7B5400F5ED55 /* QRReaderViewLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRReaderViewLauncher.swift; sourceTree = "<group>"; };
8B80569B2B5F7815009A87C8 /* SharingCredentialArgs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingCredentialArgs.swift; sourceTree = "<group>"; };
8B80569E2B60E2FB009A87C8 /* PreferencesDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesDataStore.swift; sourceTree = "<group>"; };
8B8056A02B6381BD009A87C8 /* CredentialSharingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialSharingModel.swift; sourceTree = "<group>"; };
8B81E2992B33CC4000ED3B4E /* tw2023_wallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tw2023_wallet.app; sourceTree = BUILT_PRODUCTS_DIR; };
8B81E29C2B33CC4000ED3B4E /* tw2023_walletApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tw2023_walletApp.swift; sourceTree = "<group>"; };
8B81E29E2B33CC4000ED3B4E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -886,7 +884,6 @@
children = (
8B81E2F92B35AC0C00ED3B4E /* CredentialListModel.swift */,
F657D5CE2B3C469500901A6A /* CredentialDetailModel.swift */,
8B8056A02B6381BD009A87C8 /* CredentialSharingModel.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -1652,7 +1649,6 @@
F6CC769C2B57CDB900FA26A8 /* QRCodeGenerator.swift in Sources */,
F6CC768D2B567A7B00FA26A8 /* QrCodeCameraDelegate.swift in Sources */,
F6BB10352B4FA1D60063DBBF /* RecipientOrgInfo.swift in Sources */,
8B8056A12B6381BD009A87C8 /* CredentialSharingModel.swift in Sources */,
F699A8D52B3FF6B500F60B91 /* CredentialOfferPreviewModel.swift in Sources */,
F621E1F52B6C6A610034BF95 /* RecipientDetailArgs.swift in Sources */,
A83039C92B4E6E7E004139A7 /* credential_data.proto in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/skywinder/web3swift",
"state" : {
"revision" : "74c24f4d3d5f1816616e9ebd16741ca5f7a57eb0",
"version" : "3.2.0"
"revision" : "8a026108ae5ff730ac83e9b574c8cf1c14413c94",
"version" : "3.2.2"
}
},
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class CredentialListViewModel {
let ret = matchVcToRequirement(
sdJwt: credential.payload, presentationDefinition: presentationDefinition)
if let (_, disclosures) = ret {
return 0 < disclosures.filter { it in (it.isUserSelectable || it.isSubmit) }.count
return 0
< disclosures.filter { it in (it.isUserSelectable || it.isSubmit) }.count
}
return false
}
Expand Down
14 changes: 6 additions & 8 deletions tw2023_wallet/Feature/Credentials/Views/CredentialDetail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import SwiftUI
struct CredentialDetail: View {
@Environment(\.presentationMode) var presentationMode
@Environment(SharingRequestModel.self) var sharingRequestModel: SharingRequestModel?
// @Environment(CredentialSharingModel.self) var credentialSharingModel: CredentialSharingModel?
var credential: Credential
var viewModel: CredentialDetailViewModel
var deleteAction: (() -> Void)?
Expand Down Expand Up @@ -145,17 +144,16 @@ struct CredentialDetail: View {
ActionButtonBlack(
title: "Select This Credential",
action: {
let claims = (viewModel.requiredClaims + userSelectableClaims).filter
{ it in
it.isSubmit
}
let claims = (viewModel.requiredClaims + userSelectableClaims)
.filter { it in
it.isSubmit
}
let submissionCredential = viewModel.createSubmissionCredential(
credential: credential,
discloseClaims: claims
)
sharingRequestModel?.setSelectedCredential(
data: submissionCredential,
submissionClaims: claims,
sharingRequestModel?.setSelectedCredentials(
data: [submissionCredential],
metadata: credential.metaData
)
path.removeLast(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@ class SharingRequestModel {
}

var type: String? = nil
var data: SubmissionCredential? = nil
var data: [SubmissionCredential]? = nil
var metadata: CredentialIssuerMetadata? = nil
var submissionClaims: [DisclosureWithOptionality]? = nil
func setSelectedCredential(
data: SubmissionCredential, submissionClaims: [DisclosureWithOptionality],
func setSelectedCredentials(
data: [SubmissionCredential],
metadata: CredentialIssuerMetadata
) {
self.data = data
self.submissionClaims = submissionClaims
self.metadata = metadata
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ struct SharingRequest: View {
viewModel.selectedCredential
{
let result = await viewModel.shareVpToken(
credentials: [sharingRequestModel.data!]
credentials: sharingRequestModel.data!
)
switch result {
case .success(let postResult):
Expand Down Expand Up @@ -213,11 +213,12 @@ struct SharingRequest: View {
if sharingRequestModel.data != nil {
viewModel.selectedCredential = true
if let submission = sharingRequestModel.data,
let metadata = sharingRequestModel.metadata
let metadata = sharingRequestModel.metadata,
let firstSubmission = submission.first // Workaround until multiple credentials are possible on the UI.
{
if let credentialSupported = VCIMetadataUtil.findMatchingCredentials(
format: submission.format,
types: submission.types,
format: firstSubmission.format,
types: firstSubmission.types,
metadata: metadata
) {
if let display = credentialSupported.display {
Expand Down
72 changes: 36 additions & 36 deletions tw2023_wallet/Services/OID/OpenIdProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -432,12 +432,12 @@ class OpenIdProvider {
}

let vpTokens = try! credentials.compactMap {
credential -> (String, (String, DescriptorMap, [DisclosedClaim], String?))? in
credential -> (String, PreparedSubmissionData)? in
switch credential.format {
case "vc+sd-jwt":
return (
credential.id,
try createPresentationSubmissionSdJwtVc(
try createVpTokenForSdJwtVc(
credential: credential,
presentationDefinition: presentationDefinition,
clientId: clientId,
Expand All @@ -448,7 +448,7 @@ class OpenIdProvider {
case "jwt_vc_json":
return (
credential.id,
try createPresentationSubmissionJwtVc(
try createVpTokenForJwtVc(
credential: credential,
presentationDefinition: presentationDefinition,
clientId: clientId,
Expand All @@ -463,10 +463,10 @@ class OpenIdProvider {

let vpTokenValue: String
if vpTokens.count == 1 {
vpTokenValue = vpTokens[0].1.0
vpTokenValue = vpTokens[0].1.vpToken
}
else if !vpTokens.isEmpty {
let tokens = vpTokens.map { $0.1.0 }
let tokens = vpTokens.map { $0.1.vpToken }
let jsonEncoder = JSONEncoder()
if let jsonData = try? jsonEncoder.encode(tokens),
let jsonString = String(data: jsonData, encoding: .utf8)
Expand All @@ -484,7 +484,7 @@ class OpenIdProvider {
let presentationSubmission = PresentationSubmission(
id: UUID().uuidString,
definitionId: presentationDefinition.id,
descriptorMap: vpTokens.map { $0.1.1 }
descriptorMap: vpTokens.map { $0.1.descriptorMap }
)

let jsonEncoder = JSONEncoder()
Expand All @@ -507,20 +507,22 @@ class OpenIdProvider {
convert: convertVpTokenResponseResponse,
using: session
)
let sharedContents = vpTokens.map { SharedContent(id: $0.0, sharedClaims: $0.1.2) }
let purposes = vpTokens.map { $0.1.3 }
let sharedContents = vpTokens.map {
SharedContent(id: $0.0, sharedClaims: $0.1.disclosedClaims)
}
let purposes = vpTokens.map { $0.1.purpose }
return .success((postResult, sharedContents, purposes))
}
catch {
return .failure(error)
}
}
func createPresentationSubmissionSdJwtVc(
func createVpTokenForSdJwtVc(
credential: SubmissionCredential,
presentationDefinition: PresentationDefinition,
clientId: String,
nonce: String
) throws -> (String, DescriptorMap, [DisclosedClaim], String?) {
) throws -> PreparedSubmissionData {
// ここに実装を追加します
let sdJwt = credential.credential

Expand All @@ -529,14 +531,7 @@ class OpenIdProvider {
let (inputDescriptor, _) = matchVcToRequirement(
sdJwt: sdJwt, presentationDefinition: presentationDefinition)
else {
// TODO: エラーハンドリングかダミーの戻り値
return (
"Dummy",
DescriptorMap(
id: "dummyId", format: "dummyFormat", path: "dummyPath",
pathNested: Path(format: "dummyFormat", path: "dummyPath")), [DisclosedClaim](),
"dummyPurpose"
)
throw OpenIdProviderIllegalInputException.illegalCredentialInput
}
let selectedDisclosures = credential.discloseClaims.map { $0.disclosure }
print(String(describing: inputDescriptor))
Expand All @@ -548,13 +543,7 @@ class OpenIdProvider {

let parts = sdJwt.split(separator: "~").map(String.init)
guard let issuerSignedJwt = parts.first else {
return (
"Error",
DescriptorMap(
id: "error", format: "error", path: "error",
pathNested: Path(format: "error", path: "error")), [DisclosedClaim](),
"dummyPurpose"
)
throw OpenIdProviderIllegalInputException.illegalCredentialInput
}

let hasNilValue = selectedDisclosures.contains { disclosure in
Expand Down Expand Up @@ -585,14 +574,16 @@ class OpenIdProvider {
id: credential.id, types: credential.types, name: key, value: disclosure.value)
}

return (vpToken, dm, disclosedClaims, inputDescriptor.purpose)
return PreparedSubmissionData(
vpToken: vpToken, descriptorMap: dm, disclosedClaims: disclosedClaims,
purpose: inputDescriptor.purpose)
}

func createPresentationSubmissionJwtVc(
func createVpTokenForJwtVc(
credential: SubmissionCredential,
presentationDefinition: PresentationDefinition,
clientId: String, nonce: String
) throws -> (String, DescriptorMap, [DisclosedClaim], String?) {
) throws -> PreparedSubmissionData {
do {
let (_, payload, _) = try JWTUtil.decodeJwt(jwt: credential.credential)
if let vcDictionary = payload["vc"] as? [String: Any],
Expand All @@ -613,11 +604,11 @@ class OpenIdProvider {

let descriptorMap = JwtVpJsonPresentation.genDescriptorMap(
inputDescriptorId: credential.inputDescriptor.id)
return (
vpToken,
descriptorMap,
disclosedClaims,
nil
return PreparedSubmissionData(
vpToken: vpToken,
descriptorMap: descriptorMap,
disclosedClaims: disclosedClaims,
purpose: nil
)
}
else {
Expand Down Expand Up @@ -727,6 +718,13 @@ struct SubmissionCredential: Codable, Equatable {
}
}

struct PreparedSubmissionData {
let vpToken: String
let descriptorMap: DescriptorMap
let disclosedClaims: [DisclosedClaim]
let purpose: String?
}

struct DisclosedClaim: Codable {
let id: String // credential identifier
let types: [String]
Expand Down Expand Up @@ -811,7 +809,8 @@ func matchVcToRequirement(sdJwt: String, presentationDefinition: PresentationDef
// 各InputDescriptorをループ
for inputDescriptor in presentationDefinition.inputDescriptors {
// fieldKeysを取得
let requiredOrOptionalKeys = filterKeysWithOptionality(from: sourcePayload, using: inputDescriptor)
let requiredOrOptionalKeys = filterKeysWithOptionality(
from: sourcePayload, using: inputDescriptor)

let matchingDisclosures = createDisclosureWithOptionality(
from: allDisclosures,
Expand All @@ -831,7 +830,7 @@ private func filterKeysWithOptionality(
/*
array of (String, Bool) values filtered by `inputDescriptor.constraints.fields.path`
A Bool value represents whether the field is required.

example of input_descriptors
"input_descriptors": [
{
Expand Down Expand Up @@ -870,7 +869,8 @@ private func createDisclosureWithOptionality(
disclosure: disclosure, isSubmit: !optionality, isUserSelectable: optionality)
}
}
return DisclosureWithOptionality(disclosure: disclosure, isSubmit: false, isUserSelectable: false)
return DisclosureWithOptionality(
disclosure: disclosure, isSubmit: false, isUserSelectable: false)
}
}

Expand Down
2 changes: 1 addition & 1 deletion tw2023_wallet/Services/OID/PresentationExchange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ struct PresentationSubmission: Codable {

struct DisclosureWithOptionality: Codable {
var disclosure: Disclosure

// If the value of `isUserSelectable` is `true`, the value of `isSubmit`
// is a mutable that can be changed by the user (via toggle operation).
var isSubmit: Bool
Expand Down
Loading

0 comments on commit 0b6f704

Please sign in to comment.