Advertisement
Guest User

Untitled

a guest
Jul 31st, 2017
518
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.64 KB | None | 0 0
  1. //: [Previous](@previous)
  2.  
  3.  
  4. import Foundation
  5.  
  6. URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)
  7.  
  8.  
  9. public struct FailerMessage {
  10.  
  11. var to: [String] = []
  12. var cc: [String]? = []
  13. var bcc: [String]? = []
  14. var from: String
  15. var subject: String
  16. var body: String?
  17. var attachments: [Data]? = []
  18.  
  19. }
  20.  
  21. public enum FailerError: Error {
  22. case internalFailerError
  23. case unableToConnectToHost
  24. }
  25.  
  26. public final class Failer: NSObject {
  27.  
  28. public typealias Login = (username: String, password: String)
  29.  
  30. open var server: String
  31. open var port: Int
  32. open var login: Login?
  33.  
  34. fileprivate var inputStream: InputStream!
  35. fileprivate var outputStream: OutputStream!
  36.  
  37. fileprivate let maxReadLength = 1024
  38.  
  39.  
  40. // MARK: Initialization
  41.  
  42. public init(server: String, port: Int = 25, login: Login? = nil) {
  43. self.server = server
  44. self.port = port
  45. self.login = login
  46. }
  47.  
  48. // MARK: Sending
  49.  
  50. public func send(_ message: FailerMessage) throws {
  51. try connect()
  52. let emailData: Data = try compile(message: message)
  53. try send(emailData)
  54. }
  55.  
  56. // MARK: Connection
  57.  
  58. private func connect() throws {
  59. var input: InputStream? = nil
  60. var output: OutputStream? = nil
  61.  
  62. Stream.getStreamsToHost(withName: server, port: port, inputStream: &input, outputStream: &output)
  63.  
  64. guard let inputSafe = input, let outputSafe = output else {
  65. throw FailerError.unableToConnectToHost
  66. }
  67.  
  68. self.inputStream = inputSafe
  69. self.outputStream = outputSafe
  70.  
  71. // TODO: Authentication using login
  72.  
  73. // Enable SSL/TLS on the streams
  74. // inputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySocketSecurityLevel as String))
  75. // outputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySocketSecurityLevel as String))
  76. //
  77. // // Define custom SSL/TLS settings
  78. // let sslSettings: [NSString : Any] = [
  79. // NSStream automatically sets up the socket, the streams and creates a trust object and evaulates it before you even get a chance to check the trust yourself. Only proper SSL certificates will work with this method. If you have a self signed certificate like I do, you need to disable the trust check here and evaulate the trust against your custom root CA yourself.
  80. // NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
  81. // //
  82. // NSString(format: kCFStreamSSLPeerName): kCFNull,
  83. // // We are an SSL/TLS client, not a server
  84. // NSString(format: kCFStreamSSLIsServer): kCFBooleanFalse,
  85. //
  86. // NSString(format: kCFStreamSocketSecurityLevelNegotiatedSSL): kCFBooleanTrue
  87. // ]
  88. //
  89. // // Set the SSL/TLS settingson the streams
  90. // inputStream!.setProperty(sslSettings, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySSLSettings as String))
  91. // outputStream!.setProperty(sslSettings, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySSLSettings as String))
  92.  
  93.  
  94. inputStream.delegate = self
  95. outputStream.delegate = self
  96.  
  97. inputStream.schedule(in: .main, forMode: .commonModes)
  98. outputStream.schedule(in: .main, forMode: .commonModes)
  99.  
  100. inputStream.open()
  101. outputStream.open()
  102. }
  103.  
  104. private func compile(message: FailerMessage) throws -> Data {
  105. let headersString = headers(from: message)
  106. guard var emailData = headersString.data(using: String.Encoding.utf8) else {
  107. throw FailerError.internalFailerErrorq
  108. }
  109. if let attachment = try attachments(from: message) {
  110. emailData.append(attachment)
  111. }
  112.  
  113.  
  114.  
  115. return emailData
  116. }
  117.  
  118. private func send(_ data: Data) throws {
  119. print(data)
  120. _ = data.withUnsafeBytes {
  121. outputStream.write($0, maxLength: data.count)
  122. }
  123. }
  124.  
  125. fileprivate func finish() {
  126. inputStream.close()
  127. outputStream.close()
  128. }
  129.  
  130. }
  131.  
  132. fileprivate extension Failer {
  133.  
  134. func headers(from message: FailerMessage) -> String {
  135. var content = "From: \(message.from)\r\n"
  136. content += "To: \(message.to.joined(separator: ", "))\r\n"
  137. if let cc = message.cc, cc.count > 0 {
  138. content += "Cc: \(cc.joined(separator: ", "))\r\n"
  139. }
  140. if let bcc = message.bcc, bcc.count > 0 {
  141. content += "Bcc: \(bcc.joined(separator: ", "))\r\n"
  142. }
  143. content += "Subject: \(message.subject)\r\n"
  144. // TODO: Handle email body
  145. content += "\r\n"
  146.  
  147. return content
  148. }
  149.  
  150. func attachments(from message: FailerMessage) throws -> Data? {
  151. return nil
  152. }
  153.  
  154. }
  155.  
  156. extension Failer: StreamDelegate {
  157.  
  158. public func stream(_ aStream: Stream, handle eventCode: Stream.Event)
  159. {
  160. switch eventCode
  161. {
  162. case Stream.Event.endEncountered:
  163. print("socked died")
  164. aStream.close()
  165. aStream.remove(from: RunLoop.main, forMode: .defaultRunLoopMode)
  166. break
  167. case Stream.Event.hasSpaceAvailable:
  168. print("matching presented certificate with expected")
  169.  
  170. var sslInfo: SecTrust? = aStream.property(forKey: kCFStreamPropertySSLContext as Stream.PropertyKey) as! SecTrust?
  171. sslInfo = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
  172. sslInfo = aStream.property(forKey: kCFStreamSSLValidatesCertificateChain as Stream.PropertyKey) as! SecTrust?
  173. sslInfo = aStream.property(forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey) as! SecTrust?
  174. sslInfo = aStream.property(forKey: kCFStreamSSLLevel as Stream.PropertyKey) as! SecTrust?
  175. sslInfo = aStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as! SecTrust?
  176. print(sslInfo ?? "notnin'")
  177.  
  178. // Get the presented certificate
  179. let sslTrustInput: SecTrust? = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
  180. if (sslTrustInput == nil) {
  181. print("something went horribly wrong in fetching the presented certificate")
  182. broadcastSocketResult(result: false)
  183. return
  184. }
  185.  
  186. // if (Vars.expectedCert == nil) {
  187. // print("probably a bug, there is no expected certificate in Vars. fail/crash in 3, 2, 1...")
  188. // broadcastSocketResult(result: false)
  189. // return
  190. // }
  191.  
  192. //set the expected certificate as the only "trusted" one
  193. // let acceptedCerts: NSMutableArray = NSMutableArray()
  194. // acceptedCerts.add(Vars.expectedCert!)
  195. // SecTrustSetAnchorCertificates(sslTrustInput!, acceptedCerts)
  196.  
  197. //check the certificate match test results
  198.  
  199. var result: SecTrustResultType = SecTrustResultType.fatalTrustFailure //must initialize with something
  200. let err: OSStatus = SecTrustEvaluate(sslTrustInput!, &result)
  201. if (err != errSecSuccess) {
  202. print("problem evaluating certificate match")
  203. broadcastSocketResult(result: false)
  204. return
  205. }
  206. if (result != SecTrustResultType.proceed) {
  207. print("certificate was not signed by private CA")
  208. broadcastSocketResult(result: false)
  209. return
  210. }
  211. print("socket ssl turned out ok")
  212. broadcastSocketResult(result: true)
  213. break
  214. case Stream.Event.openCompleted:
  215. print("Socket is useable")
  216. break
  217. case Stream.Event.errorOccurred:
  218. print("Error: \(aStream.streamError)")
  219. broadcastSocketResult(result: false)
  220. break;
  221. default:
  222. print("Some other code" + String(describing: eventCode))
  223. broadcastSocketResult(result: false)
  224. break
  225. }
  226. }
  227.  
  228. private func broadcastSocketResult(result: Bool) {
  229. //let extras = [Const.BORADCAST_SOCKET_RESULT: result]
  230. //NotificationCenter.default.post(name: NSNotification.Name(rawValue: Const.BROADCAST_SOCKET), object: extras)
  231. }
  232.  
  233.  
  234. private func readAvailableBytes(stream: InputStream) {
  235. let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxReadLength)
  236.  
  237. while stream.hasBytesAvailable {
  238. let numberOfBytesRead = inputStream.read(buffer, maxLength: maxReadLength)
  239.  
  240. if numberOfBytesRead < 0 {
  241. if let _ = inputStream.streamError {
  242. break
  243. }
  244. }
  245.  
  246. if let output = processedMessageString(buffer: buffer, length: numberOfBytesRead) {
  247. print(output)
  248. }
  249. }
  250. }
  251.  
  252. private func processedMessageString(buffer: UnsafeMutablePointer<UInt8>, length: Int) -> String? {
  253. let string = String(bytesNoCopy: buffer, length: length, encoding: .ascii, freeWhenDone: true)
  254. return string
  255. }
  256. }
  257.  
  258.  
  259. let failer = Failer(server: "smtp.gmail.com", port: 25, login: nil)
  260. let message = FailerMessage(to: ["ondrej.rafaj@gmail.com"], cc: nil, bcc: nil, from: "smtptesteu@gmail.com", subject: "Test subject Yo!", body: "Ondrej has a beautiful body", attachments: nil)
  261. do {
  262. try failer.send(message)
  263. }
  264. catch {
  265. print("Failer error: \(error)")
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement