// // CardData.swift // PSCB-OOS-iOS // // Created by Antonov Ilia on 21.10.2020. // import Foundation import PassKit public enum CardDataError: Error { case invalidExiryDate(String) case invalidCvCode case invalidPan } /// Billing info. /// Detailed card information public struct CardData { let pan: String let expiryYear: Int let expiryMonth: Int let cardholder: String? let cvCode: String /// Constructs card data from all necessary for billing fields /// /// - Parameters: /// - pan: Card number /// - expiryYear: A full year number (e.g: `2020`). For production cannot be in the past /// - expiryMonth: A month number from 1 to 12. /// - cvCode: CVC/CVV number /// - cardholder: (Optional) Cardholder name in latin. /// /// - Returns: optional instance of a new card. If validation fails returns nil public init?(pan: String, expiryYear: Int, expiryMonth: Int, cvCode: String, cardholder: String? = nil) { guard expiryMonth >= 1 && expiryMonth <= 12 else { print("Month can be between 1 and 12") return nil } #if !DEBUG // todo check year + month in the past let currentYear = Calendar.current.component(.year, from: Date()) guard expiryYear >= currentYear else { print("Year must be current or in the future") return nil } #endif self.pan = pan self.expiryMonth = expiryMonth self.expiryYear = expiryYear self.cvCode = cvCode self.cardholder = cardholder } /// - Returns: A last 2 digits of the expiry year public func getExpYearString() -> String { return String(String(expiryYear).dropFirst(2)) } /// - Returns: A zero padded expiry month string public func getExpMonthString() -> String { return expiryMonth < 10 ? "0\(self.expiryMonth)" : String(self.expiryMonth) } } extension CardData { internal static let pubKey: Data = { let key = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPQsWyHaynwoc2tuMbengf1SFase9tPnwtPh4o1tR+94xsWztADdhhUaUBk/68ipaoZE8uSnM9UgdEPmOotFXyUCAwEAAQ==" return Data(base64Encoded: key)! }() /// Produces a cryptogram string from given `CardData` /// See: https://docs.pscb.ru/oos/shpa.html#shlyuz-prozrachnoj-avtorizacii-sozdanie-platezha-otvet /// /// - Returns: a Base64 encoded cryptogram string public func toCryptgramString() throws -> String { let month = self.getExpMonthString() let year = self.getExpYearString() let joinedString = "\(self.pan)|\(month)|\(year)|\(cvCode)\(self.cardholder ?? "")" let base64Encode = try RSAHelper.encryptEncodeBase64(message: joinedString) return base64Encode } }