Created
April 5, 2019 07:56
-
-
Save YannisDC/c3fef28ff24684797bbdeb85f82eec55 to your computer and use it in GitHub Desktop.
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
import Cocoa | |
fileprivate extension CodingUserInfoKey { | |
static let fragmentBoxedType = CodingUserInfoKey(rawValue: "CodingUserInfoKey.fragmentBoxedType")! | |
} | |
extension JSONDecoder { | |
private struct FragmentDecodingBox<T : Decodable> : Decodable { | |
var value: T | |
init(from decoder: Decoder) throws { | |
let type = decoder.userInfo[.fragmentBoxedType] as! T.Type | |
var container = try decoder.unkeyedContainer() | |
self.value = try container.decode(type) | |
} | |
} | |
private func copy() -> JSONDecoder { | |
let decoder = JSONDecoder() | |
decoder.dataDecodingStrategy = dataDecodingStrategy | |
decoder.dateDecodingStrategy = dateDecodingStrategy | |
decoder.keyDecodingStrategy = keyDecodingStrategy | |
decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy | |
decoder.userInfo = userInfo | |
return decoder | |
} | |
public func decode<T : Decodable> ( _ type: T.Type, from data: Data, allowFragments: Bool ) throws -> T { | |
guard allowFragments else { return try decode(type, from: data) } | |
if "\(T.self)" == "String" { return String(data: data, encoding: .utf8) as! T } | |
let jsonObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) | |
let boxedData = try JSONSerialization.data(withJSONObject: [jsonObject]) | |
let decoder = copy() | |
decoder.userInfo[.fragmentBoxedType] = type | |
return try decoder.decode(FragmentDecodingBox<T>.self, from: boxedData).value | |
} | |
} | |
struct Person: Codable { | |
let name: String | |
let age: Int | |
let friends: [Person]? | |
} | |
let person = Person(name: "Brad", age: 53, friends: nil) | |
protocol Identifiable { | |
var uuid: String { get set } | |
} | |
protocol Encryptable { | |
var encrypted: Bool { get } | |
func encrypt() | |
func decrypt() | |
} | |
public class EncryptableProperty<T: Codable>: Encryptable, Codable { | |
var value: T | |
var encryptedValue: String | |
var encrypted: Bool | |
init(value: T, encrypted: Bool) { | |
self.value = value | |
self.encrypted = encrypted | |
self.encryptedValue = "" | |
} | |
func encrypt() { | |
if value is LosslessStringConvertible, let value = value as? LosslessStringConvertible { | |
self.encryptedValue = value.description | |
} else { | |
do { | |
let object = try JSONEncoder().encode(value) | |
// Do actual encryption and get the signature back | |
if let string = String(data: object, encoding: .utf8) { | |
print(string) | |
encryptedValue = string | |
} else { | |
print("not a valid UTF-8 sequence") | |
} | |
} catch{ | |
print("Encoding failed") | |
} | |
} | |
} | |
func decrypt() { | |
do { | |
let data : [UInt8] = [UInt8](self.encryptedValue.utf8) | |
// Do actual decryption and get the data back | |
let object = try JSONDecoder().decode(T.self, from: Data(data), allowFragments: true) | |
self.value = object | |
} catch{ | |
print("Decoding failed") | |
} | |
} | |
} | |
protocol EncryptableObject: Codable { | |
func encryptObject() | |
func decryptObject() | |
} | |
struct Test: EncryptableObject, Identifiable { | |
public let array: EncryptableProperty<Array<String>> | |
public let person: EncryptableProperty<Person> | |
public let string: EncryptableProperty<String> | |
var uuid: String | |
init(uuid: String = UUID().uuidString) { | |
self.array = EncryptableProperty<Array<String>>(value: ["one", "two"], encrypted: true) | |
self.person = EncryptableProperty<Person>(value: Person(name: "Brad", age: 53, friends: nil), encrypted: true) | |
self.string = EncryptableProperty<String>(value: "Test", encrypted: true) | |
self.uuid = uuid | |
} | |
func encryptObject() { | |
print("\nEncryption happens") | |
Mirror(reflecting: self) | |
.children | |
.forEach { (property) in | |
if let encryptableValue = property.value as? Encryptable { | |
encryptableValue.encrypt() | |
} | |
} | |
} | |
func decryptObject() { | |
print("\nDecryption happens") | |
Mirror(reflecting: self) | |
.children | |
.forEach { (property) in | |
if let encryptableValue = property.value as? Encryptable { | |
encryptableValue.decrypt() | |
} | |
} | |
} | |
} | |
let test = Test() | |
print("Value= \(test.array.value) EncryptedValue= \(test.array.encryptedValue)") | |
test.encryptObject() | |
print("Value= \(test.array.value) EncryptedValue= \(test.array.encryptedValue)") | |
print("\nDecrypted value gets updated") | |
test.array.encryptedValue = #"["sir", "yannis"]"# | |
print("Value= \(test.array.value) EncryptedValue= \(test.array.encryptedValue)") | |
test.decryptObject() | |
print("Value= \(test.array.value) EncryptedValue= \(test.array.encryptedValue)") | |
do { | |
let testJson = try JSONEncoder().encode(test) | |
if let string = String(data: testJson, encoding: .utf8) { | |
print(string) | |
} else { | |
print("not a valid UTF-8 sequence") | |
} | |
} catch { | |
print("FAIL") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment