-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Base Card, PDF417 and MRZ Scanners (#29)
- generic multi-credential base card (+ credential pack) - a generic PDF417 scanner - an initial MRZ (OCR) scanner based on the first QR Code scanner implementation - refactors the previous QR Code Scanner version --------- Co-authored-by: Gregorio <[email protected]>
- Loading branch information
1 parent
6067a78
commit 80e798d
Showing
12 changed files
with
1,311 additions
and
254 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,17 @@ | ||
import Foundation | ||
|
||
public class Credential: Identifiable { | ||
open class Credential: Identifiable { | ||
public var id: String | ||
|
||
public init(id: String) { | ||
self.id = id | ||
} | ||
|
||
open func get(keys: [String]) -> [String: GenericJSON] { | ||
if keys.contains("id") { | ||
return ["id": GenericJSON.string(self.id)] | ||
} else { | ||
return [:] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import Foundation | ||
import CryptoKit | ||
|
||
public class CredentialPack { | ||
|
||
private var credentials: [Credential] | ||
|
||
public init() { | ||
self.credentials = [] | ||
} | ||
|
||
public init(credentials: [Credential]) { | ||
self.credentials = credentials | ||
} | ||
|
||
public func addW3CVC(credentialString: String) throws -> [Credential]? { | ||
do { | ||
let credential = try W3CVC(credentialString: credentialString) | ||
self.credentials.append(credential) | ||
return self.credentials | ||
} catch { | ||
throw error | ||
} | ||
} | ||
|
||
public func addMDoc(mdocBase64: String, keyAlias: String = UUID().uuidString) throws -> [Credential]? { | ||
let mdocData = Data(base64Encoded: mdocBase64)! | ||
let credential = MDoc(fromMDoc: mdocData, namespaces: [:], keyAlias: keyAlias)! | ||
self.credentials.append(credential) | ||
return self.credentials | ||
} | ||
|
||
public func get(keys: [String]) -> [String: [String: GenericJSON]] { | ||
var values: [String: [String: GenericJSON]] = [:] | ||
for cred in self.credentials { | ||
values[cred.id] = cred.get(keys: keys) | ||
} | ||
|
||
return values | ||
} | ||
|
||
public func get(credentialsIds: [String]) -> [Credential] { | ||
return self.credentials.filter { credentialsIds.contains($0.id) } | ||
} | ||
|
||
public func get(credentialId: String) -> Credential? { | ||
if let credential = self.credentials.first(where: { $0.id == credentialId }) { | ||
return credential | ||
} else { | ||
return nil | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// GenericJSON implementation based on https://github.com/iwill/generic-json-swift | ||
import Foundation | ||
|
||
public enum GenericJSON { | ||
case string(String) | ||
case number(Double) | ||
case object([String: GenericJSON]) | ||
case array([GenericJSON]) | ||
case bool(Bool) | ||
case null | ||
} | ||
|
||
extension GenericJSON: Codable { | ||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
switch self { | ||
case let .array(array): | ||
try container.encode(array) | ||
case let .object(object): | ||
try container.encode(object) | ||
case let .string(string): | ||
try container.encode(string) | ||
case let .number(number): | ||
try container.encode(number) | ||
case let .bool(bool): | ||
try container.encode(bool) | ||
case .null: | ||
try container.encodeNil() | ||
} | ||
} | ||
|
||
public func toString() -> String { | ||
switch self { | ||
case .string(let str): | ||
return str | ||
case .number(let num): | ||
return num.debugDescription | ||
case .bool(let bool): | ||
return bool.description | ||
case .null: | ||
return "null" | ||
default: | ||
let encoder = JSONEncoder() | ||
encoder.outputFormatting = [.prettyPrinted] | ||
return try! String(data: encoder.encode(self), encoding: .utf8)! | ||
} | ||
} | ||
|
||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.singleValueContainer() | ||
if let object = try? container.decode([String: GenericJSON].self) { | ||
self = .object(object) | ||
} else if let array = try? container.decode([GenericJSON].self) { | ||
self = .array(array) | ||
} else if let string = try? container.decode(String.self) { | ||
self = .string(string) | ||
} else if let bool = try? container.decode(Bool.self) { | ||
self = .bool(bool) | ||
} else if let number = try? container.decode(Double.self) { | ||
self = .number(number) | ||
} else if container.decodeNil() { | ||
self = .null | ||
} else { | ||
throw DecodingError.dataCorrupted( | ||
.init(codingPath: decoder.codingPath, debugDescription: "Invalid JSON value.") | ||
) | ||
} | ||
} | ||
} | ||
|
||
extension GenericJSON: CustomDebugStringConvertible { | ||
public var debugDescription: String { | ||
switch self { | ||
case .string(let str): | ||
return str.debugDescription | ||
case .number(let num): | ||
return num.debugDescription | ||
case .bool(let bool): | ||
return bool.description | ||
case .null: | ||
return "null" | ||
default: | ||
let encoder = JSONEncoder() | ||
encoder.outputFormatting = [.prettyPrinted] | ||
return try! String(data: encoder.encode(self), encoding: .utf8)! | ||
} | ||
} | ||
} | ||
|
||
public extension GenericJSON { | ||
var dictValue: [String: GenericJSON]? { | ||
if case .object(let value) = self { | ||
return value | ||
} | ||
return nil | ||
} | ||
var arrayValue: [GenericJSON]? { | ||
if case .array(let value) = self { | ||
return value | ||
} | ||
return nil | ||
} | ||
subscript(index: Int) -> GenericJSON? { | ||
if case .array(let arr) = self, arr.indices.contains(index) { | ||
return arr[index] | ||
} | ||
return nil | ||
} | ||
|
||
subscript(key: String) -> GenericJSON? { | ||
if case .object(let dict) = self { | ||
return dict[key] | ||
} | ||
return nil | ||
} | ||
|
||
subscript(dynamicMember member: String) -> GenericJSON? { | ||
return self[member] | ||
} | ||
|
||
subscript(keyPath keyPath: String) -> GenericJSON? { | ||
return queryKeyPath(keyPath.components(separatedBy: ".")) | ||
} | ||
|
||
func queryKeyPath<T>(_ path: T) -> GenericJSON? where T: Collection, T.Element == String { | ||
guard case .object(let object) = self else { | ||
return nil | ||
} | ||
guard let head = path.first else { | ||
return nil | ||
} | ||
guard let value = object[head] else { | ||
return nil | ||
} | ||
let tail = path.dropFirst() | ||
return tail.isEmpty ? value : value.queryKeyPath(tail) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import Foundation | ||
|
||
enum W3CError: Error { | ||
case initializationError(String) | ||
} | ||
|
||
public class W3CVC: Credential { | ||
private let credentialString: String | ||
private let credential: GenericJSON? | ||
|
||
public init(credentialString: String) throws { | ||
self.credentialString = credentialString | ||
if let data = credentialString.data(using: .utf8) { | ||
do { | ||
let json = try JSONDecoder().decode(GenericJSON.self, from: data) | ||
self.credential = json | ||
super.init(id: json["id"]!.toString()) | ||
} catch let error as NSError { | ||
throw error | ||
} | ||
} else { | ||
self.credential = nil | ||
super.init(id: "") | ||
throw W3CError.initializationError("Failed to process credential string.") | ||
} | ||
} | ||
|
||
override public func get(keys: [String]) -> [String: GenericJSON] { | ||
if let cred = credential!.dictValue { | ||
return cred.filter { keys.contains($0.key) } | ||
} else { | ||
return [:] | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.