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

PR-4469: support drop in config schema #9

Merged
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
69 changes: 45 additions & 24 deletions Sources/PayrailsCSE/PayrailsCSE.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,16 @@ public struct PayrailsCSE {
var cseConfig: CSEConfiguration?

public init(data: String, version: String) {
print("Initializing config of version", version)
let config = parseConfig(data: data)
cseConfig = config
}

public func encryptCardData(card: Card) throws -> String {
let jsonCard = try JSONEncoder().encode(card)

guard let cseConfig = cseConfig else {
throw NSError(domain: "ConfigError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Missing Config"])
}

let header = JWEHeader(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .A256CBCHS512)

let publicKey: SecKey = try getPublicKey(cseConfig.tokenization.publicKey)
let publicKey: SecKey = try getPublicKey(extractPublicKey())
let encrypter = Encrypter(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .A256CBCHS512, encryptionKey: publicKey)!
let jwe = try! JWE(header: header, payload: Payload(jsonCard), encrypter: encrypter)

Expand All @@ -52,6 +47,10 @@ public struct PayrailsCSE {
throw NSError(domain: "ConfigError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Missing Config"])
}

guard let tokenization = cseConfig.tokenization else {
throw NSError(domain: "ConfigError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Missing tokenization config"])
}

let card = Card(
holderReference: cseConfig.holderReference,
cardNumber: cardNumber,
Expand All @@ -62,24 +61,24 @@ public struct PayrailsCSE {
)

let encryptedCard = try! encryptCardData(card: card)
guard let tokenizeURL = URL(string: cseConfig.tokenization.links.tokenize.href) else {
guard let tokenizeURL = URL(string: tokenization.links.tokenize.href) else {
throw NSError(domain: "URLParsingError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])
}


var request = URLRequest(url: tokenizeURL)
request.httpMethod = cseConfig.tokenization.links.tokenize.method
request.httpMethod = tokenization.links.tokenize.method
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(cseConfig.token)", forHTTPHeaderField: "Authorization")
request.setValue(UUID().uuidString, forHTTPHeaderField: "x-idempotency-key")

let encoder = JSONEncoder()
let jsonRequest = try encoder.encode(TokenizationRequest(
id: cseConfig.tokenization.id,
id: tokenization.id,
holderReference: cseConfig.holderReference,
encryptedInstrumentDetails: encryptedCard,
futureUsage: futureUsage,
storeInstrument: storeInstrument
storeInstrument: storeInstrument,
vaultProviderConfigId: tokenization.vaultProviderConfigId
))
request.httpBody = jsonRequest

Expand All @@ -101,7 +100,7 @@ public struct PayrailsCSE {

if httpResponse.statusCode == 201 {
let jsonResponse = try JSONDecoder().decode(Instrument.self, from: data)

completion(.success(TokenizeResponse(code: httpResponse.statusCode, instrument: jsonResponse, errors: nil)))
return
} else {
Expand Down Expand Up @@ -152,21 +151,35 @@ public struct PayrailsCSE {

return publicKeyRef
}

private func extractPublicKey() throws -> String {
guard let cseConfig = cseConfig else {
throw NSError(domain: "ConfigError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Missing Config"])
}

if let tokenization = cseConfig.tokenization {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this part where the logic is independent of the provider type. One question though - will there ever be a case where we have both?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kumaraksi Could be, but in that case shouldn't the publicKey be the same?

return tokenization.publicKey
} else if let vaultConfiguration = cseConfig.vaultConfiguration {
return vaultConfiguration.encryptionPublicKey
} else {
throw NSError(domain: "Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Missing publicKey in configuration"])
}
}
}

public struct Card: Codable {
var holderReference: String
var cardNumber: String
var expiryMonth: String
var expiryYear: String
var holderName: String?
var securityCode: String?
public var holderReference: String?
public var cardNumber: String?
public var expiryMonth: String?
public var expiryYear: String?
public var holderName: String?
public var securityCode: String?

public init(
holderReference: String,
cardNumber: String,
expiryMonth: String,
expiryYear: String,
holderReference: String?,
cardNumber: String?,
expiryMonth: String?,
expiryYear: String?,
holderName: String?,
securityCode: String?
) {
Expand All @@ -185,18 +198,26 @@ struct TokenizationRequest: Codable {
let encryptedInstrumentDetails: String
let futureUsage: FutureUsage?
let storeInstrument: Bool?
let vaultProviderConfigId: String?
}

struct CSEConfiguration: Codable {
let token: String
let holderReference: String
let tokenization: Tokenization
let tokenization: Tokenization?
let vaultConfiguration: VaultConfiguration?
}

struct VaultConfiguration: Codable {
let encryptionPublicKey: String
let providerConfigId: String?
}

struct Tokenization: Codable {
let id: UUID
let publicKey: String
let links: Links
let vaultProviderConfigId: String?
}

struct Links: Codable {
Expand Down
54 changes: 54 additions & 0 deletions Tests/PayrailsCSETests/PayrailsCSETests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,58 @@ import XCTest
@testable import PayrailsCSE

final class PayrailsCSETests: XCTestCase {

func testConfigInitialization() {

// Tokenization config
let data = "eyJ0b2tlbiI6ImV5SmhiR2NpT2lKU1V6STFOaUlzSW10cFpDSTZJalV4TURneE5qYzRMV1ppWXpFdE5ETXlNQzA1WkRnMkxUUTRabUU1WW1ZM01tVXdNQ0lzSW5SNWNDSTZJa3BYVkNKOS5leUpoZFdRaU9sc2lhSFIwY0RvdkwyeHZZMkZzYUc5emREbzRNRGd6TDJGMWRHZ2lYU3dpWlhod0lqb3hOekEyTURBNE5EY3lMQ0pvZEhSd2N6b3ZMM0JoZVhKaGFXeHpMbWx2TDJOc1lXbHRjeTlqZFhOMGIyMWZjMk52Y0dVaU9pSjdYQ0poYkd4dmQzTkJiR3hjSWpwbVlXeHpaU3hjSW1WNFpXTjFkR2x2Ymtsa1hDSTZYQ0pjSWl4Y0ltaHZiR1JsY2xKbFptVnlaVzVqWlZ3aU9sd2laV1ptWVhSY0lpeGNJblJ2YTJWdWFYcGhkR2x2Ymtsa1hDSTZYQ0ppWldZNE1qQTNZUzB4WmpRNUxUUXdNMll0T1RZMk15MWhPRGxoTURRNE9ESmxNbVZjSWl4Y0luUjVjR1ZjSWpwY0ltTnNhV1Z1ZEZ3aWZTSXNJbWx6Y3lJNkluQmhlWEpoYVd4eklpd2lhMmxrSWpvaU5URXdPREUyTnpndFptSmpNUzAwTXpJd0xUbGtPRFl0TkRobVlUbGlaamN5WlRBd0lpd2ljR1Z5YldsemMybHZibk1pT2xzaVkyeHBaVzUwT21WNFpXTjFkR2x2Ym5NNllYVjBhRzl5YVhwbElpd2lZMnhwWlc1ME9tVjRaV04xZEdsdmJuTTZZMjl1Wm1seWJTSXNJbU5zYVdWdWREcGxlR1ZqZFhScGIyNXpPbkpsWVdRaUxDSmpiR2xsYm5RNmFXNXpkSEoxYldWdWRITTZZM0psWVhSbElpd2lZMnhwWlc1ME9tbHVjM1J5ZFcxbGJuUnpPblJ2YTJWdWFYcGxJbDBzSW5OMVlpSTZJbTFsY21Ob1lXNTBMWE5rYXlKOS5ubzdwU2tUdVRlQkdKXzZMdE5ZTVppYmdUQzBYemYtcW5VZWxLVjl2a29ucDNIOV85S1FDNlVwQzhLM0dlcjNaUlFFLTc4dUM0cjBVSnl1dkpfSEh4SHNfNWd6U2FOOEVaNGNVWmFSYzhEZWVGdnM2T3VMWnI2VjgtUWQ5aVQ4cmxIMUJCUG43UGhRUFJ4NHhvTVl0Wlc4NlFUbTVnbWJHOEpsX0xJcDVPNE15ZkVnZDFCbGt2VjY0Z1lGOWxjaGgycGxUb1JnUVh6cjZwVFkxTDh2aVQxc1BOZlJWZHA3dUVuN3hhMmNyRDdET1JnUlZyUmJ2dC1zUHYyX1R1aFgzaGxYZkJfYjBvZmtSTW5hMDVVdWJiZkQwaGFaNnpIOERqREowdHFxMHl3ckdWWGJPNzV1YjdmTGdxbFdUcnBGQWU5VmV5OVhKdjZuaHFnOGx3TEpOQmciLCJob2xkZXJSZWZlcmVuY2UiOiJlZmZhdCIsImFtb3VudCI6eyJ2YWx1ZSI6IjEyLjUwIiwiY3VycmVuY3kiOiJFVVIifSwidG9rZW5pemF0aW9uIjp7ImlkIjoiYmVmODIwN2EtMWY0OS00MDNmLTk2NjMtYTg5YTA0ODgyZTJlIiwicHVibGljS2V5IjoiTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUE1dGpTSGVLSVhtdEUybHZTRFZtY1pVeFFCc1RLdm5VTlZhZGNWeTRJQllpaDNUN3cyalUyald6S2hoeWNiYlBSZzcvcFpTWEY0aDhzNG9WZnhTSUxRN3NKRno3L2NUaVQzejAvbXR2aGdpQjdqZGZ3VTliblRmRG9INS9CMlZKZmlJcmlncWdzeXFiYzJ5RW5Xa2tjOURtUG9ybldsQ3NpL3YzMGY3WlhGU0szUStXRmFTQ1dGQUtYTXlyNHZnSXp5dkYvYi9CM3R2Si9LYXhBMnVMTFl6d2FpamZBVjcrQWJyZVFONmxmYXJ5NmZKQmJkVkNEZmlaMWFGY2VhMFRiZ0VLbWZ0dkI1OHd1bG5hOU4xYlluUFhFRnhUaVM0cFVScUxmUmNZNWRyTWVlOUFsNHhadEl3Q0M2ZXA2ZjN4ZzlxbkJYbVovckhhYzNTRTV2aG40ZFFJREFRQUIiLCJ2YXVsdFByb3ZpZGVyQ29uZmlnSWQiOiJiMjRmZjAwNy03MjhjLTQ1NWQtYjUxYy01NTYxMDhjY2RmNTkiLCJsaW5rcyI6eyJ0b2tlbml6ZSI6eyJtZXRob2QiOiJQT1NUIiwiaHJlZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvcGF5bWVudC9pbnN0cnVtZW50cy90b2tlbml6ZSJ9fX19"

let version = "1.0.0"

let cse = PayrailsCSE.init(data: data, version: version)
XCTAssertNotNil(cse.cseConfig?.tokenization, "Expected tokenization config to exist")
}

func testCallingTokenizeWithDropInConfig() {
let data = "eyJ0b2tlbiI6ImV5SmhiR2NpT2lKU1V6STFOaUlzSW10cFpDSTZJalV4TURneE5qYzRMV1ppWXpFdE5ETXlNQzA1WkRnMkxUUTRabUU1WW1ZM01tVXdNQ0lzSW5SNWNDSTZJa3BYVkNKOS5leUpoZFdRaU9sc2lhSFIwY0RvdkwyeHZZMkZzYUc5emREbzRNRGd6TDJGMWRHZ2lYU3dpWlhod0lqb3hOekEyTURJeE16WXlMQ0pvZEhSd2N6b3ZMM0JoZVhKaGFXeHpMbWx2TDJOc1lXbHRjeTlqZFhOMGIyMWZjMk52Y0dVaU9pSjdYQ0poYkd4dmQzTkJiR3hjSWpwbVlXeHpaU3hjSW1WNFpXTjFkR2x2Ymtsa1hDSTZYQ0l3WWpkaFpqZ3laQzFpTW1FNExUUTFZVE10T1dVMllpMWxaR1UzWkdKaU56SXhNVEJjSWl4Y0ltaHZiR1JsY2xKbFptVnlaVzVqWlZ3aU9sd2laV1ptWVhSY0lpeGNJblJ2YTJWdWFYcGhkR2x2Ymtsa1hDSTZYQ0pjSWl4Y0luUjVjR1ZjSWpwY0ltTnNhV1Z1ZEZ3aWZTSXNJbWx6Y3lJNkluQmhlWEpoYVd4eklpd2lhMmxrSWpvaU5URXdPREUyTnpndFptSmpNUzAwTXpJd0xUbGtPRFl0TkRobVlUbGlaamN5WlRBd0lpd2ljR1Z5YldsemMybHZibk1pT2xzaVkyeHBaVzUwT21WNFpXTjFkR2x2Ym5NNllYVjBhRzl5YVhwbElpd2lZMnhwWlc1ME9tVjRaV04xZEdsdmJuTTZZMjl1Wm1seWJTSXNJbU5zYVdWdWREcGxlR1ZqZFhScGIyNXpPbkpsWVdRaUxDSmpiR2xsYm5RNmFXNXpkSEoxYldWdWRITTZZM0psWVhSbElpd2lZMnhwWlc1ME9tbHVjM1J5ZFcxbGJuUnpPblJ2YTJWdWFYcGxJbDBzSW5OMVlpSTZJbTFsY21Ob1lXNTBMWE5rYXlKOS5nb1dmdndKSWVYVFdqT0xSRy10T2F6bHE0VjNpNC0waW9RQklqcFVqNVhiUVlKdkVQY2N4ZUMzLVZ0Q2xINWhxRW1BNHcyMTIxbkhSRjBHZnZyYWc2R29zYUxkWkJUemhqdFVfcHgxSkxlUFhFVW90OFFOSXFGYmNWY0FtTkxOTmgteUdxaGJ1UlN3d2N5S05JcmhxUy1seF9qNlhERkc0TnlIellZQk5adGNyT2hwOGVONEh4a3RKMkppWVc4aWdmNVZnckVKTXpRWjFydEN4OWtZLW4tMUJuRDJJZnp6dnhIcUd6ODRRWkhlMkU4eEVxVDBkTGdqUVdrNy1vbjZtbEtyMTZOLTM0TkxSbnN2Q1l0YUp1TThOczRHZ0h5OVJSOXlLNnliZi1sMGUxdHBOY1RPdXVYdk92YzBXbk1tZm1WOUVLdFp6cUpOcENrbjZxT3pQU3ciLCJob2xkZXJSZWZlcmVuY2UiOiJlZmZhdCIsImFtb3VudCI6eyJ2YWx1ZSI6IjEyLjUwIiwiY3VycmVuY3kiOiJFVVIifSwiZXhlY3V0aW9uIjp7ImlkIjoiMGI3YWY4MmQtYjJhOC00NWEzLTllNmItZWRlN2RiYjcyMTEwIiwic3RhdHVzIjpbeyJjb2RlIjoiY3JlYXRlZCIsInRpbWUiOiIyMDI0LTAxLTIzVDEzOjU0OjIxLjMwMzE3ODk2MloifV0sImNyZWF0ZWRBdCI6IjIwMjQtMDEtMjNUMTM6NTQ6MjEuMzAzMTc4OTYyWiIsIm1lcmNoYW50UmVmZXJlbmNlIjoib3JkZXItYzg3NDg2NzctMTZmOS00OThmLTk1ODMtY2FmYjI0MzliYjU5IiwiaG9sZGVySWQiOiJiNjFlMjQ2Zi00YzAzLTRmMjUtYjgyMS1lMDQ5NzMzNTUwMzMiLCJob2xkZXJSZWZlcmVuY2UiOiJlZmZhdCIsImFtb3VudCI6eyJ2YWx1ZSI6IjEyLjUwIiwiY3VycmVuY3kiOiJFVVIifSwid29ya2Zsb3ciOnsiY29kZSI6InBheW1lbnQtYWNjZXB0YW5jZSIsInZlcnNpb24iOjJ9LCJtZXRhIjp7IkNJVCI6dHJ1ZSwiYWxsb3dOYXRpdmUzRFMiOmZhbHNlLCJjbGllbnRDb250ZXh0Ijp7ImlwQWRkcmVzcyI6IjIxNy4xMTAuMjM5LjEzMiIsIm9yaWdpbiI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJvc1R5cGUiOiJpb3MifSwiY3VzdG9tZXIiOnsiY291bnRyeSI6eyJjb2RlIjoiREUifSwicmVmZXJlbmNlIjoiZWZmYXQifSwib3JkZXIiOnsicmVmZXJlbmNlIjoib3JkZXItYzg3NDg2NzctMTZmOS00OThmLTk1ODMtY2FmYjI0MzliYjU5In0sInZhdWx0VHlwZSI6IlBheXJhaWxzIn0sImxpbmtzIjp7InNlbGYiOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL21lcmNoYW50L3dvcmtmbG93cy9wYXltZW50LWFjY2VwdGFuY2UvZXhlY3V0aW9ucy8wYjdhZjgyZC1iMmE4LTQ1YTMtOWU2Yi1lZGU3ZGJiNzIxMTAiLCJhdXRob3JpemUiOnsibWV0aG9kIjoiUE9TVCIsImhyZWYiOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL21lcmNoYW50L3dvcmtmbG93cy9wYXltZW50LWFjY2VwdGFuY2UvZXhlY3V0aW9ucy8wYjdhZjgyZC1iMmE4LTQ1YTMtOWU2Yi1lZGU3ZGJiNzIxMTAvYXV0aG9yaXplIn0sInN0YXJ0UGF5bWVudFNlc3Npb24iOnsibWV0aG9kIjoiUE9TVCIsImhyZWYiOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL21lcmNoYW50L3dvcmtmbG93cy9wYXltZW50LWFjY2VwdGFuY2UvZXhlY3V0aW9ucy8wYjdhZjgyZC1iMmE4LTQ1YTMtOWU2Yi1lZGU3ZGJiNzIxMTAvc3RhcnRQYXltZW50U2Vzc2lvbiJ9fSwiaW5pdGlhbFJlc3VsdHMiOlt7Imh0dHBDb2RlIjoyMDAsImJvZHkiOnsibmFtZSI6Imxvb2t1cCIsImFjdGlvbklkIjoiYzcyZWEyOTYtZGYzNC00MDVjLTllYzMtODliNTczYjQ4OWUzIiwiZXhlY3V0ZWRBdCI6IjIwMjQtMDEtMjNUMTM6NTQ6MjIuMjY4ODkyMjk1WiIsImRhdGEiOnsicGF5bWVudENvbXBvc2l0aW9uT3B0aW9ucyI6W3siaW50ZWdyYXRpb25UeXBlIjoiYWR5ZW5Ecm9wSW4iLCJkZXNjcmlwdGlvbiI6IkFkeWVuIERyb3AtSW4ifSx7ImludGVncmF0aW9uVHlwZSI6ImFwaSIsInBheW1lbnRNZXRob2RDb2RlIjoiYXBwbGVQYXkiLCJkZXNjcmlwdGlvbiI6IkFwcGxlUGF5IiwiY29uZmlnIjp7InBhcmFtZXRlcnMiOnsiY291bnRyeUNvZGUiOiJERSIsIm1lcmNoYW50Q2FwYWJpbGl0aWVzIjpbInN1cHBvcnRzM0RTIiwic3VwcG9ydHNDcmVkaXQiLCJzdXBwb3J0c0RlYml0Il0sIm1lcmNoYW50SWRlbnRpZmllciI6Im1lcmNoYW50LnBheXJhaWxzLnRlc3RpbmciLCJzdXBwb3J0ZWROZXR3b3JrcyI6WyJBTUVYIiwiRElTQ09WRVIiLCJJTlRFUkFDIiwiSkNCIiwiVklTQSIsIk1BU1RFUkNBUkQiXX0sInR5cGUiOiJDQVJEIn19XX0sImxpbmtzIjp7ImV4ZWN1dGlvbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzBiN2FmODJkLWIyYTgtNDVhMy05ZTZiLWVkZTdkYmI3MjExMCIsImF1dGhvcml6ZSI6eyJtZXRob2QiOiJQT1NUIiwiaHJlZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzBiN2FmODJkLWIyYTgtNDVhMy05ZTZiLWVkZTdkYmI3MjExMC9hdXRob3JpemUifSwic3RhcnRQYXltZW50U2Vzc2lvbiI6eyJtZXRob2QiOiJQT1NUIiwiaHJlZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzBiN2FmODJkLWIyYTgtNDVhMy05ZTZiLWVkZTdkYmI3MjExMC9zdGFydFBheW1lbnRTZXNzaW9uIn19fX1dfX0="

let version = "1.0.0"

let cse = PayrailsCSE.init(data: data, version: version)

do {
try cse.tokenize(
cardNumber: "4242424242424242",
expiryMonth: "12",
expiryYear: "30") { (result: Result<TokenizeResponse, Error>) in }
} catch let error as NSError {
XCTAssertEqual(error.domain, "ConfigError")
XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as? String, "Missing tokenization config")
} catch {
XCTFail("Unexpected error type: \(error)")
}
}

func testCallingEncryptCarDataWithDropInConfig() {
let data = "eyJ0b2tlbiI6ImV5SmhiR2NpT2lKU1V6STFOaUlzSW10cFpDSTZJalpsTnpSbE9HUXdMVGt4TlRrdE5ERTJZeTA1TUdabUxUUmtOMk5oWldNMFptSTNOU0lzSW5SNWNDSTZJa3BYVkNKOS5leUpoZFdRaU9sc2lhSFIwY0RvdkwyeHZZMkZzYUc5emREbzRNRGd6TDJGMWRHZ2lYU3dpWlhod0lqb3hOekEyTVRJMU16QXpMQ0pvZEhSd2N6b3ZMM0JoZVhKaGFXeHpMbWx2TDJOc1lXbHRjeTlqZFhOMGIyMWZjMk52Y0dVaU9pSjdYQ0poYkd4dmQzTkJiR3hjSWpwbVlXeHpaU3hjSW1WNFpXTjFkR2x2Ymtsa1hDSTZYQ0kyWldVNE5qaGtOUzB4TlRjd0xUUXpZVEl0T1RsbFlpMWhOalZoT1RWbE5HRmlOamRjSWl4Y0ltaHZiR1JsY2xKbFptVnlaVzVqWlZ3aU9sd2laV1ptWVhSY0lpeGNJblJ2YTJWdWFYcGhkR2x2Ymtsa1hDSTZYQ0pjSWl4Y0luUjVjR1ZjSWpwY0ltTnNhV1Z1ZEZ3aWZTSXNJbWx6Y3lJNkluQmhlWEpoYVd4eklpd2lhMmxrSWpvaU5tVTNOR1U0WkRBdE9URTFPUzAwTVRaakxUa3dabVl0TkdRM1kyRmxZelJtWWpjMUlpd2ljR1Z5YldsemMybHZibk1pT2xzaVkyeHBaVzUwT21WNFpXTjFkR2x2Ym5NNllYVjBhRzl5YVhwbElpd2lZMnhwWlc1ME9tVjRaV04xZEdsdmJuTTZZMjl1Wm1seWJTSXNJbU5zYVdWdWREcGxlR1ZqZFhScGIyNXpPbkpsWVdRaUxDSmpiR2xsYm5RNmFXNXpkSEoxYldWdWRITTZZM0psWVhSbElpd2lZMnhwWlc1ME9tbHVjM1J5ZFcxbGJuUnpPblJ2YTJWdWFYcGxJbDBzSW5OMVlpSTZJbTFsY21Ob1lXNTBMWE5rYXlKOS5ob3QtbE0wNHlwUEwtWHhYZ1ljSXQ0S3h3MTVLa1RGVGdzQWI2WHJYQXp1eFlEcFk3Y0RmZHhjZC16aVlDT05zUElxUWt2M05tWkRsOEU5aFl2bTlLb3o4MFhoejd6ZFA2SENtendVbXhrMHhoN3FlWm9DV0toV0U3VjdNX2hpckFWdnFkM2F3TjQ3d1ZlMlNISTVVd1lMYmtZNW41dXBySTQtS01Qb0E4SmVaNzVvWGctQ1NnV1VDUDV5RFB6R3cxVFZfMUQ4UDZabksySHN0LTBEeVVVN1kxRlZSQ1JKRFZadUVqUi01T2Y2UzVuZDRZZTFacnNhbUZrRnVPOUs3c3RlbHNFT0NNcXpQZkpBbHR4cUE1SkxoZDhQX2tXQS1iWUtWRGJWTmtvMFU1NXlLUktnam5pUFpZTmhCN2NzOWtaNTJTMFkxMjBvVGpHN2UxUk9DUWciLCJob2xkZXJSZWZlcmVuY2UiOiJlZmZhdCIsInZhdWx0Q29uZmlndXJhdGlvbiI6eyJ2YXVsdElkIjoiIiwidmF1bHRVcmwiOiIiLCJ0b2tlbiI6IiIsInN0YXR1cyI6ImVuYWJsZWQiLCJ2YXVsdFR5cGUiOiJQYXlyYWlscyIsInByb3ZpZGVySWQiOiJkZjMwMmRiZS02ZDUzLTRkN2MtYTkzMi05NzMzYzZjMTI4NmYiLCJwcm92aWRlckNvbmZpZ0lkIjoiYjI0ZmYwMDctNzI4Yy00NTVkLWI1MWMtNTU2MTA4Y2NkZjU5IiwibGlua3MiOnsic2F2ZUluc3RydW1lbnQiOnsibWV0aG9kIjoiUE9TVCIsImhyZWYiOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL3BheW1lbnQvaW5zdHJ1bWVudHMifX0sImVuY3J5cHRpb25QdWJsaWNLZXkiOiJNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXp5SDJpUlhoeVZLUlJOaGowUU1iUFRXNC9BSUd4bk43ZjFYcURzdTBvOXoxbEJLQ2tDaVc4YklLb1JhV0ZkVVludXdHclEyQ0R3MllOMlptcktFcnhUWm5PWEpIVHk1ek1EMG1panpTUEYxZXNkUndXSy83RG5laTJkMzdFbjJoOCtsQ3NKSjJYeElIbUUyRko5Z0JLYnEwY0RtOXYwNWRJaFNlSU54NW92Y1RTQWhIRzNKTHZXTFJWcy9oT2Nubi92bE93R01Oa2RhdElzQU5vNjZDZG1rWFNRNFFCWUY4TFVTZVZmWEtBYjFDVjVqcmkzQlMyckZEb1pZME1iVTZjLzlENzRieHJjaFlEbEZFNEFhL3dRbjFKTTZ4R005YllQTStiL1F1T0NNNmJtK0Z2THZsTGZYWTBoVFhSWkpldmR6YmJFQnV4ZU4yUnhpVlMrSytsd0lEQVFBQiJ9LCJhbW91bnQiOnsidmFsdWUiOiIxMi41MCIsImN1cnJlbmN5IjoiRVVSIn0sImV4ZWN1dGlvbiI6eyJpZCI6IjZlZTg2OGQ1LTE1NzAtNDNhMi05OWViLWE2NWE5NWU0YWI2NyIsInN0YXR1cyI6W3siY29kZSI6ImNyZWF0ZWQiLCJ0aW1lIjoiMjAyNC0wMS0yNFQxODo0Njo0My4zNDMxMTYwNVoifV0sImNyZWF0ZWRBdCI6IjIwMjQtMDEtMjRUMTg6NDY6NDMuMzQzMTE2MDVaIiwibWVyY2hhbnRSZWZlcmVuY2UiOiJvcmRlci00YTc2M2VkMS05ZTVkLTRiMTYtOTQ2My03ZTA4YmJjYWMyMjQiLCJob2xkZXJJZCI6ImM0ZTlkMGQ4LTljMTQtNDhhYi1iMGY5LTdkYWRkYTcyNDZmZCIsImhvbGRlclJlZmVyZW5jZSI6ImVmZmF0IiwiYW1vdW50Ijp7InZhbHVlIjoiMTIuNTAiLCJjdXJyZW5jeSI6IkVVUiJ9LCJ3b3JrZmxvdyI6eyJjb2RlIjoicGF5bWVudC1hY2NlcHRhbmNlIiwidmVyc2lvbiI6M30sIm1ldGEiOnsiQ0lUIjp0cnVlLCJhbGxvd05hdGl2ZTNEUyI6ZmFsc2UsImNsaWVudENvbnRleHQiOnsiaXBBZGRyZXNzIjoiMjE3LjExMC4yMzkuMTMyIiwib3JpZ2luIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsIm9zVHlwZSI6ImlvcyJ9LCJjdXN0b21lciI6eyJjb3VudHJ5Ijp7ImNvZGUiOiJERSJ9LCJyZWZlcmVuY2UiOiJlZmZhdCJ9LCJvcmRlciI6eyJyZWZlcmVuY2UiOiJvcmRlci00YTc2M2VkMS05ZTVkLTRiMTYtOTQ2My03ZTA4YmJjYWMyMjQifSwidmF1bHRUeXBlIjoiUGF5cmFpbHMifSwibGlua3MiOnsic2VsZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzZlZTg2OGQ1LTE1NzAtNDNhMi05OWViLWE2NWE5NWU0YWI2NyIsImF1dGhvcml6ZSI6eyJtZXRob2QiOiJQT1NUIiwiaHJlZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzZlZTg2OGQ1LTE1NzAtNDNhMi05OWViLWE2NWE5NWU0YWI2Ny9hdXRob3JpemUifSwic3RhcnRQYXltZW50U2Vzc2lvbiI6eyJtZXRob2QiOiJQT1NUIiwiaHJlZiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4Ni9wdWJsaWMvbWVyY2hhbnQvd29ya2Zsb3dzL3BheW1lbnQtYWNjZXB0YW5jZS9leGVjdXRpb25zLzZlZTg2OGQ1LTE1NzAtNDNhMi05OWViLWE2NWE5NWU0YWI2Ny9zdGFydFBheW1lbnRTZXNzaW9uIn19LCJpbml0aWFsUmVzdWx0cyI6W3siaHR0cENvZGUiOjIwMCwiYm9keSI6eyJuYW1lIjoibG9va3VwIiwiYWN0aW9uSWQiOiIyNTc4NGNmNy04M2NiLTQwOWYtYWE2Ny01N2RjMDgxYjliZGEiLCJleGVjdXRlZEF0IjoiMjAyNC0wMS0yNFQxODo0Njo0My40MTc1MjYwOTNaIiwiZGF0YSI6eyJwYXltZW50Q29tcG9zaXRpb25PcHRpb25zIjpbeyJpbnRlZ3JhdGlvblR5cGUiOiJhcGkiLCJwYXltZW50TWV0aG9kQ29kZSI6ImNhcmQiLCJkZXNjcmlwdGlvbiI6IkNhcmQifV19LCJsaW5rcyI6eyJleGVjdXRpb24iOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL21lcmNoYW50L3dvcmtmbG93cy9wYXltZW50LWFjY2VwdGFuY2UvZXhlY3V0aW9ucy82ZWU4NjhkNS0xNTcwLTQzYTItOTllYi1hNjVhOTVlNGFiNjciLCJhdXRob3JpemUiOnsibWV0aG9kIjoiUE9TVCIsImhyZWYiOiJodHRwOi8vbG9jYWxob3N0OjgwODYvcHVibGljL21lcmNoYW50L3dvcmtmbG93cy9wYXltZW50LWFjY2VwdGFuY2UvZXhlY3V0aW9ucy82ZWU4NjhkNS0xNTcwLTQzYTItOTllYi1hNjVhOTVlNGFiNjcvYXV0aG9yaXplIn19fX1dfX0="

let version = "1.0.0"

let cse = PayrailsCSE.init(data: data, version: version)

do {
let encryptedInstrumentDetails = try cse.encryptCardData(card: Card.self(
holderReference: "reference",
cardNumber: "4242424242424242",
expiryMonth: "12",
expiryYear: "35",
holderName: "George",
securityCode: "123"
))

XCTAssertNotNil(encryptedInstrumentDetails)
} catch {
XCTFail("Unexpected error type: \(error)")
}
}
}
Loading