Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* 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

eu-digital-green-certificates#108
eu-digital-green-certificates#111
eu-digital-green-certificates#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 <[email protected]>
Co-authored-by: Illia Vlasov <[email protected]>
Co-authored-by: Test <[email protected]>
Co-authored-by: ikhomiak <[email protected]>
Co-authored-by: IgorKhomiak <[email protected]>
  • Loading branch information
6 people authored Mar 1, 2022
1 parent db6fc44 commit d23a50c
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 62 deletions.
16 changes: 12 additions & 4 deletions DGCAWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -253,6 +255,8 @@
DA01661D26554992005B73A1 /* OpenSourceNotices.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = OpenSourceNotices.json; sourceTree = "<group>"; };
DA01661F26554E02005B73A1 /* LicenseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicenseCell.swift; sourceTree = "<group>"; };
DA01662126558B2F005B73A1 /* LicenseController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = LicenseController.swift; sourceTree = "<group>"; tabWidth = 2; };
DA5A441527CE301100E64183 /* DGCAJwt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DGCAJwt.swift; sourceTree = "<group>"; };
DA5A441727CE303600E64183 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
FE6F225327142AB1003AE754 /* dgca-app-core-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "dgca-app-core-ios"; path = "../dgca-app-core-ios"; sourceTree = "<group>"; };
FEAEA96426FBB13600B94FFF /* AccessTokenResponse.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AccessTokenResponse.swift; sourceTree = "<group>"; tabWidth = 2; };
FEBE53B42721A3EA003B61FB /* LimitationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LimitationCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -370,6 +374,7 @@
5C50CF3926973D9D0015EE29 /* UserDefaults+.swift */,
5C50CF3D26983E090015EE29 /* UITableView+.swift */,
5C00071826CFAED2002E5013 /* UIImage+String.swift */,
DA5A441727CE303600E64183 /* Data.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -436,6 +441,7 @@
5C00072126D3A40E002E5013 /* SavedImage.swift */,
5C00072D26D3AC11002E5013 /* SavedPDF.swift */,
FEAEA96426FBB13600B94FFF /* AccessTokenResponse.swift */,
DA5A441527CE301100E64183 /* DGCAJwt.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -1113,15 +1121,15 @@
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;
LD_RUNPATH_SEARCH_PATHS = (
"$(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";
Expand All @@ -1138,15 +1146,15 @@
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;
LD_RUNPATH_SEARCH_PATHS = (
"$(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";
Expand Down
38 changes: 38 additions & 0 deletions DGCAWallet/Extensions/Data.swift
Original file line number Diff line number Diff line change
@@ -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: "")
}
}
84 changes: 84 additions & 0 deletions DGCAWallet/Models/DGCAJwt.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
}
}
5 changes: 5 additions & 0 deletions DGCAWallet/Models/DataStorageManagement/DataCenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ class DataCenter {
pdfDataManager.loadLocallyStoredData { result in
group.leave()
}

group.enter()
GatewayConnection.lookup(certStrings: certStrings) { success, _, _ in
group.leave()
}
group.leave()
}

Expand Down
124 changes: 71 additions & 53 deletions DGCAWallet/Services/GatewayConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit d23a50c

Please sign in to comment.