93 lines
2.8 KiB
Swift
93 lines
2.8 KiB
Swift
//
|
|
// 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
|
|
}
|
|
|
|
}
|