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

Release -> develop #24

Merged
merged 14 commits into from
Jul 16, 2024
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
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
Loading