Skip to content

Commit

Permalink
fixes #309, #319, #334
Browse files Browse the repository at this point in the history
  • Loading branch information
daltoniam committed Jun 24, 2017
1 parent 7e517c2 commit 601ef74
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 23 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file.
`Starscream` adheres to [Semantic Versioning](http://semver.org/).

#### [2.1.0](https://github.com/daltoniam/Starscream/tree/2.1.0)

Adds WebSocket compression. Also adds advance WebSocket delegate for extra control. Bug Fixes.

[#349](https://github.com/daltoniam/Starscream/pull/349)
[#344](https://github.com/daltoniam/Starscream/pull/344)
[#337](https://github.com/daltoniam/Starscream/pull/337)
[#334](https://github.com/daltoniam/Starscream/issues/334)
[#333](https://github.com/daltoniam/Starscream/pull/333)
[#319](https://github.com/daltoniam/Starscream/issues/319)
[#309](https://github.com/daltoniam/Starscream/issues/309)

#### [2.0.4](https://github.com/daltoniam/Starscream/tree/2.0.4)

SSL Pinning fix by Giuliano Galea as reported by Lukas Futera of [Centralway](https://www.centralway.com/de/).
Expand Down
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,11 @@ socket.delegate = self
socket.connect()
```

### Self Signed SSL and VOIP

There are a couple of other properties that modify the stream:
### Self Signed SSL

```swift
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])

//set this if you are planning on using the socket in a VOIP background setting (using the background VOIP service).
socket.voipEnabled = true

//set this you want to ignore SSL cert validation, so a self signed SSL certificate can be used.
socket.disableSSLCertValidation = true
```
Expand Down
2 changes: 1 addition & 1 deletion Source/Info-tvOS.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.4</string>
<string>2.1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
2 changes: 1 addition & 1 deletion Source/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.4</string>
<string>2.1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
42 changes: 29 additions & 13 deletions Source/WebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import Foundation
import CoreFoundation
import Security
import CommonCrypto

public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification"
public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification"
Expand Down Expand Up @@ -80,6 +80,8 @@ open class WebSocket : NSObject, StreamDelegate {
// 0-999 WebSocket status codes not used
case outputStreamWriteError = 1
case compressionError = 2
case invalidSSLError = 3
case writeTimeoutError = 4
}

// Where the callback is executed. It defaults to the main UI thread queue.
Expand Down Expand Up @@ -168,7 +170,6 @@ open class WebSocket : NSObject, StreamDelegate {

public var httpMethod: HTTPMethod = .get
public var headers = [String: String]()
public var voipEnabled = false
public var disableSSLCertValidation = false
public var enableCompression = true
public var security: SSLTrustValidator?
Expand Down Expand Up @@ -207,6 +208,7 @@ open class WebSocket : NSObject, StreamDelegate {
private var certValidated = false
private var didDisconnect = false
private var readyToWrite = false
private var headerSecKey = ""
private let mutex = NSLock()
private let notificationCenter = NotificationCenter.default
private var canDispatch: Bool {
Expand Down Expand Up @@ -329,8 +331,9 @@ open class WebSocket : NSObject, StreamDelegate {
if let protocols = optionalProtocols {
addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joined(separator: ","))
}
headerSecKey = generateWebSocketKey()
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
addHeader(urlRequest, key: headerWSKeyName, val: headerSecKey)
if let origin = origin {
addHeader(urlRequest, key: headerOriginName, val: origin)
}
Expand Down Expand Up @@ -419,10 +422,6 @@ open class WebSocket : NSObject, StreamDelegate {
} else {
certValidated = true //not a https session, so no need to check SSL pinning
}
if voipEnabled {
inStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
outStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
}

CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
Expand All @@ -446,7 +445,8 @@ open class WebSocket : NSObject, StreamDelegate {
WebSocket.sharedWorkQueue.async {
self?.cleanupStream()
}
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
let errCode = InternalErrorCode.writeTimeoutError.rawValue
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: errCode))
return
} else if outStream.streamError != nil {
return // disconnectStream will be called.
Expand All @@ -460,7 +460,8 @@ open class WebSocket : NSObject, StreamDelegate {
s.certValidated = sec.isValid(trust, domain: domain)
if !s.certValidated {
WebSocket.sharedWorkQueue.async {
let error = s.errorWithDetail("Invalid SSL certificate", code: 1)
let errCode = InternalErrorCode.invalidSSLError.rawValue
let error = s.errorWithDetail("Invalid SSL certificate", code: errCode)
s.disconnectStream(error)
}
return
Expand Down Expand Up @@ -645,6 +646,12 @@ open class WebSocket : NSObject, StreamDelegate {

if let acceptKey = headers[headerWSAcceptName as NSString] as? NSString {
if acceptKey.length > 0 {
if headerSecKey.characters.count > 0 {
let sha = "\(headerSecKey)258EAFA5-E914-47DA-95CA-C5AB0DC85B11".sha1Base64()
if sha != acceptKey as String {
return -1
}
}
return 0
}
}
Expand All @@ -661,19 +668,19 @@ open class WebSocket : NSObject, StreamDelegate {
let part = p.trimmingCharacters(in: .whitespaces)
if part == "permessage-deflate" {
compressionState.supportsCompression = true
} else if part.hasPrefix("server_max_window_bits="){
} else if part.hasPrefix("server_max_window_bits=") {
let valString = part.components(separatedBy: "=")[1]
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
compressionState.serverMaxWindowBits = val
}
} else if part.hasPrefix("client_max_window_bits="){
} else if part.hasPrefix("client_max_window_bits=") {
let valString = part.components(separatedBy: "=")[1]
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
compressionState.clientMaxWindowBits = val
}
} else if part == "client_no_context_takeover"{
} else if part == "client_no_context_takeover" {
compressionState.clientNoContextTakeover = true
} else if part == "server_no_context_takeover"{
} else if part == "server_no_context_takeover" {
compressionState.serverNoContextTakeover = true
}
}
Expand Down Expand Up @@ -1082,6 +1089,15 @@ open class WebSocket : NSObject, StreamDelegate {

}

private extension String {
func sha1Base64() -> String {
let data = self.data(using: String.Encoding.utf8)!
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
return Data(bytes: digest).base64EncodedString()
}
}

private extension Data {

init(buffer: UnsafeBufferPointer<UInt8>) {
Expand Down
2 changes: 1 addition & 1 deletion Starscream.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Starscream"
s.version = "2.0.4"
s.version = "2.1.0"
s.summary = "A conforming WebSocket RFC 6455 client library in Swift for iOS and OSX."
s.homepage = "https://github.com/daltoniam/Starscream"
s.license = 'Apache License, Version 2.0'
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion zlib/include.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

#include <zlib.h>
#include <CommonCrypto/CommonCrypto.h>
4 changes: 4 additions & 0 deletions zlib/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ module zlib [system] {
header "include.h"
link "z"
}
module CommonCrypto [system] {
header "include.h"
export *
}

0 comments on commit 601ef74

Please sign in to comment.