// // Customer.swift // PrivadoVPN // // Created by Zhandos Bolatbekov on 01.02.2021. // Copyright © 2021 Privado LLC. All rights reserved. // import Foundation struct Customer: Decodable { enum Plan: Decodable { case freemium case overquota case premium(value: String) case unrecognized(value: String) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let plan = try container.decode(String.self) switch plan { case "FREE": self = .freemium case "OVERQUOTA": self = .overquota case _ where plan.hasPrefix("PREMIUM"): self = .premium(value: plan) default: self = .unrecognized(value: plan) } } } let plan: Plan? let email: String let endDate: String let username: String let isPremium: Bool let startDate: String let premiumDate: String? let serverGroup: String let trafficLeft: UInt64? let trafficTotal: UInt64? let speedLimit: Int let connectionsLimit: Int? let loginUrl: String? let isVPNActive: Bool? let localIp: String? let protocols: Protocols? enum CodingKeys: String, CodingKey { case plan = "sku" case email case endDate = "end_date" case username case isPremium = "is_premium" case startDate = "start_date" case premiumDate = "premium_date" case serverGroup = "server_group" case trafficLeft = "traffic_left_mb" case trafficTotal = "traffic_total_mb" case speedLimit = "speed_limit_mbps" case connectionsLimit = "connections_limit" case loginUrl = "login_url" case isVPNActive = "active_vpn" case localIp = "local_ip" case protocols } struct Response: Decodable { let data: Customer? } struct Protocols: Decodable { let ios: [ConnectionPriorityType]? } internal func isEmpty() -> Bool { self.username.isEmpty } } extension Customer.Plan: Equatable { static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { case (.freemium, .freemium), (.overquota, .overquota): return true case let (.premium(lvalue), .premium(rvalue)), let (.unrecognized(lvalue), .unrecognized(rvalue)): return lvalue == rvalue default: return false } } } extension Customer: Equatable { static func == (lhs: Self, rhs: Self) -> Bool { return lhs.plan == rhs.plan && lhs.email == rhs.email && lhs.username == rhs.username && lhs.endDate == rhs.endDate && lhs.isPremium == rhs.isPremium && lhs.startDate == rhs.startDate && lhs.premiumDate == rhs.premiumDate && lhs.serverGroup == rhs.serverGroup && lhs.trafficLeft == rhs.trafficLeft && lhs.trafficTotal == rhs.trafficTotal && lhs.speedLimit == rhs.speedLimit && lhs.connectionsLimit == rhs.connectionsLimit && lhs.loginUrl == rhs.loginUrl && lhs.isVPNActive == rhs.isVPNActive } } enum ConnectionPriorityType: RawRepresentable, Decodable { enum Constant { static let prefix = "OPENVPN" } init?(rawValue: String) { let rawValue = rawValue.uppercased() if rawValue.hasPrefix(Constant.prefix) { let strArray = rawValue.split(separator: "/") let proto = OvpnProtocolType(rawValue: String(strArray[safe: 1] ?? "")) ?? .udp let port = OvpnPortType(rawValue: String(strArray[safe: 2] ?? "")) ?? .p1194 self = .ovpn(proto: proto, port: port) return } switch rawValue { case "IKEV2": self = .ikev2 case "WIREGUARD": self = .wireguard default: self = .ikev2 } } var rawValue: String { switch self { case .ikev2: return "IKEV2" case .wireguard: return "WIREGUARD" case .ovpn(proto: let proto, port: let port): let protoStr = !proto.rawValue.isEmpty ? "/\(proto.rawValue)" : "" let portStr = port.rawValue != 0 ? "/\(port.rawValue)" : "" return "OPENVPN" + protoStr + portStr } } typealias RawValue = String case ikev2 case ovpn(proto: OvpnProtocolType, port: OvpnPortType) case wireguard static let defaultPriority: [ConnectionPriorityType] = [.ikev2 , .ovpn(proto: .udp, port: .p1194)] public func ovpnSettings() -> (proto: OvpnProtocolType, port: OvpnPortType)? { switch self { case .ovpn(proto: let proto, port: let port): return (proto: proto, port: port) default: return nil } } } enum OvpnProtocolType: RawRepresentable { typealias RawValue = String var rawValue: String { switch self { case .udp: return "UDP" case .tcp: return "TCP" } } init?(rawValue: String) { switch rawValue.uppercased() { case "UDP": self = .udp case "TCP": self = .tcp default: self = .udp } } case udp case tcp } enum OvpnPortType: RawRepresentable, Decodable { typealias RawValue = Int16 var rawValue: Int16 { switch self { case .p1194: return 1194 case .none: return 0 } } init?(rawValue: Int16) { switch rawValue { case 0: self = .none case 1194: self = .p1194 default: self = .p1194 } } init?(rawValue: String) { switch rawValue { case "1194": self = .p1194 default: self = .p1194 } } case none case p1194 }