Skip to content

Commit

Permalink
PR-4406: Expose encryptCard func and Card struct (#8)
Browse files Browse the repository at this point in the history
* feat: exposed encrypt card function

* refactor: renaming encryptCard to encryptCardData

* PR-4469: support drop in config schema (#9)

* feat: support for dropIn initialization config

* fix: relax vaultConfiguration required fields

* feat: version bump to 0.2.0
  • Loading branch information
grgmgd authored Jan 31, 2024
1 parent bea75a8 commit 9f18992
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 23 deletions.
2 changes: 1 addition & 1 deletion PayrailsCSE.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'PayrailsCSE'
s.version = '0.1.1'
s.version = '0.2.0'
s.summary = 'Payrails client-side encryption SDK'

# This description is used to generate tags and improve search results.
Expand Down
81 changes: 59 additions & 22 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
}

func encryptCard(card: Card) throws -> String {
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 @@ -61,25 +60,25 @@ public struct PayrailsCSE {
securityCode: securityCode
)

let encryptedCard = try! encryptCard(card: card)
guard let tokenizeURL = URL(string: cseConfig.tokenization.links.tokenize.href) else {
let encryptedCard = try! encryptCardData(card: card)
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,15 +151,45 @@ 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 {
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?,
holderName: String?,
securityCode: String?
) {
self.holderReference = holderReference
self.cardNumber = cardNumber
self.expiryMonth = expiryMonth
self.expiryYear = expiryYear
self.holderName = holderName
self.securityCode = securityCode
}
}

struct TokenizationRequest: Codable {
Expand All @@ -169,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)")
}
}
}

0 comments on commit 9f18992

Please sign in to comment.