Skip to content

Commit

Permalink
Merge pull request #24 from OWND-Project/release
Browse files Browse the repository at this point in the history
Release -> develop
  • Loading branch information
sadamu authored Jul 16, 2024
2 parents 42bce66 + d25c7a8 commit 8337ed4
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@
// Created by 若葉良介 on 2023/12/22.
//


/*
-------------------------------------------------------------------------------
Caution!

`CredentialOfferView` will be significantly revised in PR#17,
which has been filed to make it ID1 compliant.
This PR#17 will be merged soon, but will not be included in the next release.

With that in mind, the current content below contains a stopgap measure
that was implemented to get through the next release.

-------------------------------------------------------------------------------
*/


import Foundation
import SwiftUI

Expand All @@ -14,7 +30,7 @@ enum CredentialOfferParseError: Error {
case InvalidCredentialOffer
}

class CredentialOfferViewModel {
class CredentialOfferViewModel: ObservableObject {
var dataModel: CredentialOfferModel = .init()
var rawCredentialOfferString: String? = nil

Expand Down Expand Up @@ -48,7 +64,6 @@ class CredentialOfferViewModel {

func sendRequest(userPin: String?) async throws {
do {
interpretMetadataAndOffer()

let vciClient = try await VCIClient(
credentialOfferJson:
Expand Down Expand Up @@ -105,6 +120,8 @@ class CredentialOfferViewModel {

let credentialIssuer = credentialOffer!["credential_issuer"] as! String
self.dataModel.metaData = try await retrieveAllMetadata(issuer: credentialIssuer)

interpretMetadataAndOffer()

dataModel.isLoading = false
dataModel.hasLoadedData = true
Expand Down
202 changes: 117 additions & 85 deletions tw2023_wallet/Feature/IssueCredential/Views/CredentialOffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,20 @@
// Created by 若葉良介 on 2023/12/22.
//

// AndroidのConfirmationFragment相当
// https://github.com/datasign-inc/tw2023-wallet-android/blob/3655ace01d3c454529e34f1b78a4329f44508d23/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/confirmation/ConfirmationFragment.kt#L1

/*
-------------------------------------------------------------------------------
Caution!

`CredentialOfferView` will be significantly revised in PR#17,
which has been filed to make it ID1 compliant.
This PR#17 will be merged soon, but will not be included in the next release.

With that in mind, the current content below contains a stopgap measure
that was implemented to get through the next release.

-------------------------------------------------------------------------------
*/

import SwiftUI

Expand Down Expand Up @@ -37,35 +49,19 @@ func getClaimNames(credentialSupported: CredentialSupported?) -> [String] {
struct CredentialOfferView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(CredentialOfferArgs.self) var args
var viewModel: CredentialOfferViewModel
@StateObject var viewModel: CredentialOfferViewModel = .init()
@State private var navigateToHome = false
@State private var navigateToPinInput = false
@State private var showErrorDialog = false

init(viewModel: CredentialOfferViewModel = CredentialOfferViewModel()) {
self.viewModel = viewModel
}

var body: some View {
NavigationStack {
Group {
if viewModel.dataModel.isLoading {
ProgressView().progressViewStyle(CircularProgressViewStyle())
}
else {
let issuerDisplayName = viewModel.dataModel.metaData?.display?.first?.name ?? ""
let credentialSupported = viewModel.dataModel.metaData?.credentialsSupported
.keys
let firstCredentialName = credentialSupported?.first
let targetCredential =
firstCredentialName == nil
? nil
: viewModel.dataModel.metaData?.credentialsSupported[firstCredentialName!]

let credentialDisplayName = getCredentialDisplayName(
credentialSupported: targetCredential)
let displayNames: [String] = getClaimNames(
credentialSupported: targetCredential)
private func contentWithMetaData(
issuerDisplayName: String,
credentialDisplayName: String,
displayNames: [String]
) -> some View {
GeometryReader { geometry in
ScrollView {
VStack {
HStack {
Button("Cancel") {
presentationMode.wrappedValue.dismiss()
Expand All @@ -74,67 +70,103 @@ struct CredentialOfferView: View {
.padding(.horizontal, 16)
Spacer()
}
GeometryReader { geometry in
ScrollView {
VStack {
Text(
String(
format: NSLocalizedString(
"credentialOfferText", comment: ""), issuerDisplayName,
credentialDisplayName)
)
.modifier(Title3Black())
Image("issue_confirmation")
.resizable()
.scaledToFit()
.frame(width: geometry.size.width * 0.65) // 横幅の65%に設定
}
Text("Items to be issued")
.padding(.vertical, 16)
.frame(maxWidth: .infinity, alignment: .leading) // 左寄せ
.modifier(BodyGray())
ForEach(displayNames, id: \.self) { displayName in
CredentialSubjectLow(item: displayName)

Text(
String(
format: NSLocalizedString(
"credentialOfferText", comment: ""), issuerDisplayName,
credentialDisplayName)
)
.modifier(Title3Black())
Image("issue_confirmation")
.resizable()
.scaledToFit()
.frame(width: geometry.size.width * 0.65) // 横幅の65%に設定
}
Text("Items to be issued")
.padding(.vertical, 16)
.frame(maxWidth: .infinity, alignment: .leading) // 左寄せ
.modifier(BodyGray())
ForEach(displayNames, id: \.self) { displayName in
CredentialSubjectLow(item: displayName)
}
Text("issuing_authority_information")
.frame(maxWidth: .infinity, alignment: .leading) // 左寄せ
.padding(.top, 32)
.modifier(BodyBlack())

IssuerDetail(
issuerMetadata: viewModel.dataModel.metaData, showTitle: false)
ActionButtonBlack(
title: "issue_credential",
action: {
let pinRequired = viewModel.checkIfPinIsRequired()
if pinRequired {
self.navigateToPinInput = true
}
else {
Task {
try await viewModel.sendRequest(userPin: nil)
self.navigateToHome = true
}
Text("issuing_authority_information")
.frame(maxWidth: .infinity, alignment: .leading) // 左寄せ
.padding(.top, 32)
.modifier(BodyBlack())

IssuerDetail(
issuerMetadata: viewModel.dataModel.metaData, showTitle: false)
ActionButtonBlack(
title: "issue_credential",
action: {
let pinRequired = viewModel.checkIfPinIsRequired()
if pinRequired {
self.navigateToPinInput = true
}
else {
Task {
try await viewModel.sendRequest(userPin: nil)
self.navigateToHome = true
}
}
}
)
.padding(.vertical, 16)
.navigationDestination(
isPresented: $navigateToHome,
destination: {
Home()
}
)
.navigationDestination(
isPresented: $navigateToPinInput,
destination: {
PinCodeInput(viewModel: self.viewModel)
}
)
}
.padding(.horizontal, 16) // 左右に16dpのパディング
.padding(.vertical, 16)
}
)
.padding(.vertical, 16)
.navigationDestination(
isPresented: $navigateToHome,
destination: {
Home()
}
)
.navigationDestination(
isPresented: $navigateToPinInput,
destination: {
PinCodeInput(viewModel: self.viewModel)
}
)
}
.padding(.horizontal, 16) // 左右に16dpのパディング
.padding(.vertical, 16)
}
}

@ViewBuilder
private var content: some View {

if let issuerDisplayName = viewModel.dataModel.metaData?.display?.first?.name,
let credentialName = viewModel.credential_vct,
let credentialSupported = viewModel.dataModel.metaData?.credentialsSupported,
let targetCredential = viewModel.dataModel.metaData?.credentialsSupported[
credentialName]
{

let credentialDisplayName = getCredentialDisplayName(
credentialSupported: targetCredential)
let displayNames: [String] = getClaimNames(
credentialSupported: targetCredential)

contentWithMetaData(
issuerDisplayName: issuerDisplayName, credentialDisplayName: credentialDisplayName,
displayNames: displayNames)
}
else {
EmptyView()
.onAppear {
print("Unable to load metadata")
showErrorDialog = true
}
}
}

var body: some View {
NavigationStack {
Group {
if viewModel.dataModel.isLoading {
ProgressView().progressViewStyle(CircularProgressViewStyle())
}
else {
content
}
}
.navigationBarTitle("", displayMode: .inline)
Expand Down
43 changes: 41 additions & 2 deletions tw2023_wallet/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,28 @@
}
}
},
"eventName" : {
"extractionState" : "manual",
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "イベント名"
}
}
}
},
"EventTicketCredential" : {
"extractionState" : "manual",
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "イベントチケット"
}
}
}
},
"failed_to_show_credential_offer" : {
"localizations" : {
"en" : {
Expand Down Expand Up @@ -1035,7 +1057,7 @@
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "氏名"
"value" : "イベント名"
}
}
}
Expand Down Expand Up @@ -1672,6 +1694,23 @@
}
}
},
"ticketNo" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ticket Number"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "チケット番号"
}
}
}
},
"TotalItems" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -2056,4 +2095,4 @@
}
},
"version" : "1.0"
}
}
10 changes: 8 additions & 2 deletions tw2023_wallet/Services/OID/OpenIdProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ class OpenIdProvider {
the Client Identifier MUST be a DNS name and match a dNSName Subject Alternative Name (SAN) [RFC5280] entry in the leaf certificate passed with the request.
*/
let (decoded, certificates) = verifedX5CJwt
if isDomainInSAN(certificate: certificates[0], domain: _clientId) {

guard let url = URL(string: _clientId),
let domainName = url.host else {
return .failure(.authRequestInputError(reason: .compliantError(reason: "Unable to get host name")))
}

if isDomainInSAN(certificate: certificates[0], domain: domainName) {
print("verify san entry success")
}
else {
Expand Down Expand Up @@ -399,7 +405,7 @@ class OpenIdProvider {
throw NetworkError.invalidResponse
}
}

return PostResult(statusCode: statusCode, location: nil, cookies: nil)
}

Expand Down
7 changes: 3 additions & 4 deletions tw2023_wallet/datastore/CredentialDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,9 @@ extension Datastore_CredentialData {
}
}

private func getBackgroundImage() -> String? {
private func getBackgroundImage(credentialType: String) -> String? {
guard let metaData = self.parsedMetaData(),
let supportedName = metaData.credentialsSupported.keys.first, // todo: 1つめを前提としている
let supported = metaData.credentialsSupported[supportedName],
let supported = metaData.credentialsSupported[credentialType],
let displays = supported.display,
let firstDisplay = displays.first, // todo: 1つめを前提としている
let backgroundImageUrl = firstDisplay.backgroundImage
Expand Down Expand Up @@ -161,7 +160,7 @@ extension Datastore_CredentialData {
issuer: issuer,
issuerDisplayName: issuerName,
issuedAt: iat,
backgroundImageUrl: getBackgroundImage(),
backgroundImageUrl: getBackgroundImage(credentialType: self.type),
credentialType: self.type,
disclosure: disclosure,
qrDisplay: self.generateQRDisplay(),
Expand Down
Loading

0 comments on commit 8337ed4

Please sign in to comment.