From d23a50c2da452cb42b9c7b80e7f1e2d02a7d8dff Mon Sep 17 00:00:00 2001 From: Paul B Date: Tue, 1 Mar 2022 16:25:39 +0100 Subject: [PATCH] Release/1.3.1 (#130) * no message * added new UI * Ticketing solution logic update - Added model to handle QR scan from ticket service - Added blueprint of method to obtain list of auth services * Refactored list of service method * Implemented method to fetch list of services * added new UI * server list view controller * Access token for ticketing - Request implemented - Model for response added * added selected and deselected state * List of services implemented * Public key generation added * Small refactoring to avoid crash * AccessTokenRequest fixed - Filtering for certificates added * Selection code adjusted with model * Comment removed * fixed small UI bugs * Consent screen added - request for validation added * Fixed UI part of selection of cert * xnonce added * Fixed navigation in wallet app * Fixed navigation and cells. Added Certificate controller to navigation. * Added services controller * Remove obsolete sources * Removed unnecessary fields * minor fixes * Replaced x-buttons * Removed unnecessary code * Validation request added * Refactored ut8 string to base64decoded data * Code clean up * Identity services refactored * Code clean up * Validation Result view controller added * fixed QR class * Fixed navigation * Fixed navigation * Bug fix session #108 #111 #113 * Added remove certificate functionality * Added delete alert * Fixed deleting * Fixed reload bug in ListCertificates * Add Developer Team * Changed cert compare * Fixed certificates table with edit * Added 2 controller files to storyboard * Fixed crash on verification result if no validation info passed * Update project * Scan Moved from Core * Added viewers to storyboard * Added remove messages to ImageViewer and PDF * Fixed Remove action * Removed xibs from controllers * Minor fix storyboard * Removed last xib * Fixed deleting, crash with race and some textes * Fix public in Date extention * Added activity check * Fixed crash with reload table * Added flash of added item * Added OK button * Fixed rule cell * Updated buttons * Fixed Grant layout * Minor fix * Fix crash with adding certs * minor fix * Fix selecting of sertificates * Added new version * added logsto requests * remove print * Fixed posting certificates * Added delete button * Removed FloatingPanel, Added delete certificate button * Finalized remove certificate * Fixed layout * Fixed deleting calbacks * Removed FloatingPanel package * Removed FloatingPanel resources * removed unnecessary import directives * Aded common core * Removed errors with cert * Fixed wallet app after core mege * fix in project tree * Access token info added on Certificate list screen * fixed storyboards * minor fixes * Added activity indicator * Added config * Fixed navigation issues * Fixed classe names in storyboards * fixed fetch time * Fixed reloadingData * fixed storyboard - added reload cell * Added reload after dismissing * Fixed Scan of ticketing QR code * minor changes in project tree * Fixed page controller * removed selected country code * Fixed landscape orientation for iPad * refactor UI cells * increased build num * temp data * correct data * fixed project settings * Fixed issue - Certificate for Ticketing can not be found * Added loading to confirm validity * x5c type changed in PublicKeyJWK structure Replaced x5c type of String with [String] in order to follow backend changes * Refactor controller names and data managers * fixed crash in ticketing * Business data were removed from TicketingAcceptanceController controller * Fixed back buttons * added background * Added Alerts to the Ticketing * refactor project tree * Replaced UserDefaults storage with keyChain * removed queue from request * Updated localization strings * Changed in localizations * Removed keys from Localization file * Added Safe thread array. * Fixed string format * Added de-localization * Added localisations to resource files * Added app localised name * Fixed localizations * Added localized property. Added alert on save PDF, fixed alerts * Optimised loading on main screen * Fixed reload page on main screen * Fixed layout in Image and PDF cells * Fixed reload table on main screen * upgrade version num * Fixed Localized strings * Added one line to localization * Refactored Access Token functionality * Added error processing to the ticketing * Fix verification fields * Fixed search of validation data * Fixed main thread methods * Fixed incorrect alert messages * Updated localized strings * Fixed json logic * Added revocation to walllet * removed database * removed dismiss delegate (added timer) * feat: revocation * fix: revocation lookup * chore: version 1.3.1 * fix: exp bug Co-authored-by: Alexandr Chernyy Co-authored-by: Illia Vlasov Co-authored-by: Test Co-authored-by: ikhomiak Co-authored-by: IgorKhomiak --- DGCAWallet.xcodeproj/project.pbxproj | 16 ++- DGCAWallet/Extensions/Data.swift | 38 ++++++ DGCAWallet/Models/DGCAJwt.swift | 84 ++++++++++++ .../DataStorageManagement/DataCenter.swift | 5 + DGCAWallet/Services/GatewayConnection.swift | 124 ++++++++++-------- .../Storyboards/Base.lproj/Main.storyboard | 5 - 6 files changed, 210 insertions(+), 62 deletions(-) create mode 100644 DGCAWallet/Extensions/Data.swift create mode 100644 DGCAWallet/Models/DGCAJwt.swift diff --git a/DGCAWallet.xcodeproj/project.pbxproj b/DGCAWallet.xcodeproj/project.pbxproj index 3c5fc33..c5eb74f 100644 --- a/DGCAWallet.xcodeproj/project.pbxproj +++ b/DGCAWallet.xcodeproj/project.pbxproj @@ -141,6 +141,8 @@ DA01661E26554992005B73A1 /* OpenSourceNotices.json in Resources */ = {isa = PBXBuildFile; fileRef = DA01661D26554992005B73A1 /* OpenSourceNotices.json */; }; DA01662026554E02005B73A1 /* LicenseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA01661F26554E02005B73A1 /* LicenseCell.swift */; }; DA01662226558B2F005B73A1 /* LicenseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA01662126558B2F005B73A1 /* LicenseController.swift */; }; + DA5A441627CE301100E64183 /* DGCAJwt.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5A441527CE301100E64183 /* DGCAJwt.swift */; }; + DA5A441827CE303600E64183 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5A441727CE303600E64183 /* Data.swift */; }; FE1D1A6B27148CBE00765A9A /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = FE1D1A6A27148CBE00765A9A /* CryptoSwift */; }; FE6E78882702033300C142A3 /* JWTDecode in Frameworks */ = {isa = PBXBuildFile; productRef = FE6E78872702033300C142A3 /* JWTDecode */; }; FEAEA96526FBB13600B94FFF /* AccessTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEAEA96426FBB13600B94FFF /* AccessTokenResponse.swift */; }; @@ -253,6 +255,8 @@ DA01661D26554992005B73A1 /* OpenSourceNotices.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = OpenSourceNotices.json; sourceTree = ""; }; DA01661F26554E02005B73A1 /* LicenseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicenseCell.swift; sourceTree = ""; }; DA01662126558B2F005B73A1 /* LicenseController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = LicenseController.swift; sourceTree = ""; tabWidth = 2; }; + DA5A441527CE301100E64183 /* DGCAJwt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DGCAJwt.swift; sourceTree = ""; }; + DA5A441727CE303600E64183 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; FE6F225327142AB1003AE754 /* dgca-app-core-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "dgca-app-core-ios"; path = "../dgca-app-core-ios"; sourceTree = ""; }; FEAEA96426FBB13600B94FFF /* AccessTokenResponse.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AccessTokenResponse.swift; sourceTree = ""; tabWidth = 2; }; FEBE53B42721A3EA003B61FB /* LimitationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LimitationCell.swift; sourceTree = ""; }; @@ -370,6 +374,7 @@ 5C50CF3926973D9D0015EE29 /* UserDefaults+.swift */, 5C50CF3D26983E090015EE29 /* UITableView+.swift */, 5C00071826CFAED2002E5013 /* UIImage+String.swift */, + DA5A441727CE303600E64183 /* Data.swift */, ); path = Extensions; sourceTree = ""; @@ -436,6 +441,7 @@ 5C00072126D3A40E002E5013 /* SavedImage.swift */, 5C00072D26D3AC11002E5013 /* SavedPDF.swift */, FEAEA96426FBB13600B94FFF /* AccessTokenResponse.swift */, + DA5A441527CE301100E64183 /* DGCAJwt.swift */, ); path = Models; sourceTree = ""; @@ -798,10 +804,12 @@ CE56BC07264068110044FD3F /* GatewayConnection.swift in Sources */, FEAEA96526FBB13600B94FFF /* AccessTokenResponse.swift in Sources */, CE13CF23262DDF810070C80E /* RoundedButton.swift in Sources */, + DA5A441827CE303600E64183 /* Data.swift in Sources */, 5C556D5126F9F8C6007E2C2E /* ServerListController.swift in Sources */, 5C50CF2726972BCA0015EE29 /* SimpleValidityCell.swift in Sources */, DA01662026554E02005B73A1 /* LicenseCell.swift in Sources */, CEA6D6EC261F8D2700715333 /* AppDelegate.swift in Sources */, + DA5A441627CE301100E64183 /* DGCAJwt.swift in Sources */, D2E6CB07273A94EA00E9AF1F /* LocalDataManager.swift in Sources */, DA01661C265541C0005B73A1 /* LicenseTableController.swift in Sources */, 5C00073626D625D0002E5013 /* PDFTableViewCell.swift in Sources */, @@ -1113,7 +1121,7 @@ CODE_SIGN_ENTITLEMENTS = DGCAWallet/DGCAWallet.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 9FH6TNGWF2; INFOPLIST_FILE = DGCAWallet/SupportingFiles/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; @@ -1121,7 +1129,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.3.1; + MARKETING_VERSION = 1.3.1; PRODUCT_BUNDLE_IDENTIFIER = "com.t-systems.pu-ds.dgca.wallet.dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Digital Green Certificate Wallet"; @@ -1138,7 +1146,7 @@ CODE_SIGN_ENTITLEMENTS = DGCAWallet/DGCAWallet.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 9FH6TNGWF2; INFOPLIST_FILE = DGCAWallet/SupportingFiles/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; @@ -1146,7 +1154,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.3.1; + MARKETING_VERSION = 1.3.1; PRODUCT_BUNDLE_IDENTIFIER = "com.t-systems.pu-ds.dgca.wallet.dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Digital Green Certificate Wallet"; diff --git a/DGCAWallet/Extensions/Data.swift b/DGCAWallet/Extensions/Data.swift new file mode 100644 index 0000000..410f27f --- /dev/null +++ b/DGCAWallet/Extensions/Data.swift @@ -0,0 +1,38 @@ +// +/*- + * ---license-start + * eu-digital-green-certificates / dgca-wallet-app-ios + * --- + * Copyright (C) 2021 T-Systems International GmbH and all other contributors + * --- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---license-end + */ +// +// Data.swift +// DGCAWallet +// +// Created by Paul Ballmann on 01.03.22. +// + + +import Foundation + +extension Data { + func urlSafeBase64EncodedString() -> String { + return base64EncodedString() + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "=", with: "") + } +} diff --git a/DGCAWallet/Models/DGCAJwt.swift b/DGCAWallet/Models/DGCAJwt.swift new file mode 100644 index 0000000..7ea3dbe --- /dev/null +++ b/DGCAWallet/Models/DGCAJwt.swift @@ -0,0 +1,84 @@ +// +/*- + * ---license-start + * eu-digital-green-certificates / dgca-wallet-app-ios + * --- + * Copyright (C) 2021 T-Systems International GmbH and all other contributors + * --- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---license-end + */ +// +// JWT.swift +// DGCAWallet +// +// Created by Paul Ballmann on 01.03.22. +// + + +import Foundation +import CryptoKit +import SwiftDGC + +struct Header: Encodable { + let alg = "ES256" + let typ = "JWT" +} + +struct Payload: Encodable { + let sub: String + let payload: [String] + let exp: Double +} + +class DGCAJwt { + private static func makeJwtPayload(cert: HCert) -> Payload { + let payload: [String] = [cert.uvciHash![0..<(cert.uvciHash!.count/2)].toHexString(), + cert.signatureHash![0..<(cert.signatureHash!.count/2)].toHexString(), + cert.countryCodeUvciHash![0..<(cert.countryCodeUvciHash!.count/2)].toHexString()] + return Payload(sub: cert.uvciHash!.toHexString(), payload: payload, exp: cert.exp.timeIntervalSince1970) + } + // payload: Payload, with keyPair: SecKey + public static func makeJwtAndSign(fromCerts certs: [HCert], completion: @escaping (Bool, [String]?, Error?) -> Void) { + var tokens: [String] = [] + for cert in certs { + do { + let payload = DGCAJwt.makeJwtPayload(cert: cert) + let headerDataBase64 = try JSONEncoder().encode(Header()).urlSafeBase64EncodedString() + let payloadBase64 = try JSONEncoder().encode(payload).urlSafeBase64EncodedString() + let toSign = Data((headerDataBase64 + "." + payloadBase64).utf8) + Enclave.sign(data: toSign, with: cert.keyPair, using: .ecdsaSignatureMessageX962SHA256) { sign, err in + guard err == nil else { + completion(false, nil, GatewayError.local(description: err!)) + return + } + guard let sign = sign else { + completion(false, nil, GatewayError.local(description: err!)) + return + } + let signatureBase64 = sign.urlSafeBase64EncodedString() + let token = [headerDataBase64, payloadBase64, signatureBase64].joined(separator: ".") + // completion(true, token, nil) + tokens.append(token) + if tokens.count == certs.count { + completion(true, tokens, nil) + } + } + } catch { + print(error) + completion(false, nil, error) + return + } + } + } +} diff --git a/DGCAWallet/Models/DataStorageManagement/DataCenter.swift b/DGCAWallet/Models/DataStorageManagement/DataCenter.swift index cb8bbec..0bc35bf 100644 --- a/DGCAWallet/Models/DataStorageManagement/DataCenter.swift +++ b/DGCAWallet/Models/DataStorageManagement/DataCenter.swift @@ -178,6 +178,11 @@ class DataCenter { pdfDataManager.loadLocallyStoredData { result in group.leave() } + + group.enter() + GatewayConnection.lookup(certStrings: certStrings) { success, _, _ in + group.leave() + } group.leave() } diff --git a/DGCAWallet/Services/GatewayConnection.swift b/DGCAWallet/Services/GatewayConnection.swift index a368e0a..90e4c1e 100644 --- a/DGCAWallet/Services/GatewayConnection.swift +++ b/DGCAWallet/Services/GatewayConnection.swift @@ -33,16 +33,16 @@ import CertLogic import JWTDecode enum GatewayError: Error { - case insufficientData - case encodingError - case signingError - case updatingError - case incorrectDataResponse - case connection(error: Error) - case local(description: String) - case parsingError - case privateKeyError - case tokenError + case insufficientData + case encodingError + case signingError + case updatingError + case incorrectDataResponse + case connection(error: Error) + case local(description: String) + case parsingError + case privateKeyError + case tokenError } typealias ValueSetsCompletion = ([ValueSet]?, Error?) -> Void @@ -104,60 +104,78 @@ class GatewayConnection: ContextConnection { } static func lookup(certStrings: [DatedCertString], completion: @escaping ContextCompletion) { + guard certStrings.count != 0 else { completion(true, nil, nil); return; } // construct certs from strings - var certs: [Date:HCert] = [:] + var certs: [Date: HCert] = [:] for string in certStrings { guard let c = string.cert else { completion(false, nil, nil); return; } + // certs.append(c) certs[string.date] = c } - var certHashes: [String] = [] - certs.forEach { _, cert in - certHashes.append(cert.certHash) - } - let param: [String: Any] = ["value": certHashes] - request( - [""], - externalLink: "https://dgca-revocation-service-eu-test.cfapps.eu10.hana.ondemand.com/revocation/lookup", - method: .post, - parameters: param, - encoding: JSONEncoding.default - ).response { - guard - case .success(_) = $0.result, - let status = $0.response?.statusCode, - let response = String(data: $0.data ?? .init(), encoding: .utf8), - status / 100 == 2 - else { - completion(false, nil, nil) - return - } - if response.count == 0 { completion(true, nil, nil); return } - // response is list of hashes that have been revoked - let revokedHashes = certHashes.filter { element in - return !response.contains(element) - } - for revokedHash in revokedHashes { - certs.forEach { date, cert in - if cert.certHash.elementsEqual(revokedHash) { - cert.isRevoked = true - // remove old certificate and add new - DataCenter.localDataManager.remove(withDate: date) { status in - guard case .success(_) = status else { completion(false, nil, nil); return } - var storedTan: String? - certStrings.forEach { certString in - if certString.cert!.certHash.elementsEqual(cert.certHash) { - storedTan = certString.storedTAN ?? nil - } - } - DataCenter.localDataManager.add(cert, with: storedTan) { status in + + DGCAJwt.makeJwtAndSign(fromCerts: Array(certs.values)) { success, jwts, error in + guard let jwts = jwts, + success == true, + error == nil else { + completion(false, nil, GatewayError.local(description: "JWT creation failed!")) + return + } + // let param = ["value": jwts] + + var request = URLRequest(url: URL(string: "https://dgca-revocation-service-eu-test.cfapps.eu10.hana.ondemand.com/revocation/lookup")!) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpBody = try! JSONSerialization.data(withJSONObject: jwts) + AF.request(request).response { + guard + case .success(_) = $0.result, + let status = $0.response?.statusCode, + let response = try? JSONSerialization.jsonObject(with: $0.data ?? .init(), options: []) as? [String], + status / 100 == 2 + else { + completion(false, nil, nil) + return + } + if response.count == 0 { completion(true, nil, nil); return } + // response is list of hashes that have been revoked + let revokedHashes = response as [String] + for revokedHash in revokedHashes { + certs.forEach { date, cert in + if revokedHash.elementsEqual(cert.uvciHash!.toHexString()) || + revokedHash.elementsEqual(cert.signatureHash!.toHexString()) || + revokedHash.elementsEqual(cert.countryCodeUvciHash!.toHexString()) { + cert.isRevoked = true + // remove old certificate and add new + DataCenter.localDataManager.remove(withDate: date) { status in guard case .success(_) = status else { completion(false, nil, nil); return } + var storedTan: String? + certStrings.forEach { certString in + if certString.cert!.certHash.elementsEqual(cert.certHash) { + storedTan = certString.storedTAN ?? nil + } + } + DataCenter.localDataManager.add(cert, with: storedTan) { status in + guard case .success(_) = status else { completion(false, nil, nil); return } + } } } } } - } - completion(true, nil, nil) + completion(true, nil, nil) + } + /* + request( + [""], + externalLink: "https://dgca-revocation-service-eu-test.cfapps.eu10.hana.ondemand.com/revocation/lookup", + method: .post, + parameters: param, + encoding: JSONEncoding.default + ).response { + + } */ + } + } static func fetchContext(completion: @escaping CompletionHandler) { diff --git a/DGCAWallet/Storyboards/Base.lproj/Main.storyboard b/DGCAWallet/Storyboards/Base.lproj/Main.storyboard index d41ddf2..0ea64c5 100644 --- a/DGCAWallet/Storyboards/Base.lproj/Main.storyboard +++ b/DGCAWallet/Storyboards/Base.lproj/Main.storyboard @@ -1009,7 +1009,6 @@ - @@ -1021,9 +1020,7 @@ - - @@ -1216,7 +1213,6 @@ - @@ -1224,7 +1220,6 @@ -