Skip to content

Commit 778c3e4

Browse files
committed
Update auth-related code and add new test for encoding channel name
in auth request
1 parent 90db0b7 commit 778c3e4

File tree

3 files changed

+85
-54
lines changed

3 files changed

+85
-54
lines changed

Source/PusherConnection.swift

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ open class PusherConnection: NSObject {
488488
} else if let eData = jsonObject["data"] as? [String: AnyObject] {
489489
globalChannel.handleErrorEvent(name: eventName, data: eData)
490490
}
491-
}
491+
}
492492
}
493493

494494
/**
@@ -506,68 +506,68 @@ open class PusherConnection: NSObject {
506506
subscribeToNormalChannel(channel)
507507
return true
508508
} else {
509-
if let socketID = self.socketId {
510-
switch self.options.authMethod {
511-
case .noMethod:
512-
let errorMessage = "Authentication method required for private / presence channels but none provided."
513-
let error = NSError(domain: "com.pusher.PusherSwift", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey: errorMessage])
509+
guard let socketId = self.socketId else {
510+
print("socketId value not found. You may not be connected.")
511+
return false
512+
}
514513

515-
print(errorMessage)
514+
switch self.options.authMethod {
515+
case .noMethod:
516+
let errorMessage = "Authentication method required for private / presence channels but none provided."
517+
let error = NSError(domain: "com.pusher.PusherSwift", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey: errorMessage])
516518

517-
handleAuthorizationError(forChannel: channel.name, response: nil, data: nil, error: error)
519+
print(errorMessage)
518520

519-
return false
520-
case .endpoint(authEndpoint: let authEndpoint):
521-
let request = requestForAuthValue(from: authEndpoint, socketID: socketID, channel: channel)
522-
sendAuthorisationRequest(request: request, channel: channel, callback: callback)
523-
return true
521+
handleAuthorizationError(forChannel: channel.name, response: nil, data: nil, error: error)
524522

525-
case .authRequestBuilder(authRequestBuilder: let builder):
526-
if let request = builder.requestFor?(socketID: socketID, channel: channel) {
527-
sendAuthorisationRequest(request: request as URLRequest, channel: channel, callback: callback)
523+
return false
524+
case .endpoint(authEndpoint: let authEndpoint):
525+
let request = requestForAuthValue(from: authEndpoint, socketId: socketId, channelName: channel.name)
526+
sendAuthorisationRequest(request: request, channel: channel, callback: callback)
527+
return true
528528

529-
return true
530-
} else if let request = builder.requestFor?(socketID: socketID, channelName: channel.name) {
531-
sendAuthorisationRequest(request: request, channel: channel, callback: callback)
529+
case .authRequestBuilder(authRequestBuilder: let builder):
530+
if let request = builder.requestFor?(socketID: socketId, channel: channel) {
531+
sendAuthorisationRequest(request: request as URLRequest, channel: channel, callback: callback)
532532

533-
return true
534-
} else {
535-
let errorMessage = "Authentication request could not be built"
536-
let error = NSError(domain: "com.pusher.PusherSwift", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey: errorMessage])
533+
return true
534+
} else if let request = builder.requestFor?(socketID: socketId, channelName: channel.name) {
535+
sendAuthorisationRequest(request: request, channel: channel, callback: callback)
537536

538-
handleAuthorizationError(forChannel: channel.name, response: nil, data: nil, error: error)
537+
return true
538+
} else {
539+
let errorMessage = "Authentication request could not be built"
540+
let error = NSError(domain: "com.pusher.PusherSwift", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey: errorMessage])
539541

540-
return false
541-
}
542-
case .inline(secret: let secret):
543-
var msg = ""
544-
var channelData = ""
545-
if channel.type == .presence {
546-
channelData = getUserDataJSON()
547-
msg = "\(self.socketId!):\(channel.name):\(channelData)"
548-
} else {
549-
msg = "\(self.socketId!):\(channel.name)"
550-
}
542+
handleAuthorizationError(forChannel: channel.name, response: nil, data: nil, error: error)
551543

552-
let secretBuff: [UInt8] = Array(secret.utf8)
553-
let msgBuff: [UInt8] = Array(msg.utf8)
544+
return false
545+
}
546+
case .inline(secret: let secret):
547+
var msg = ""
548+
var channelData = ""
549+
if channel.type == .presence {
550+
channelData = getUserDataJSON()
551+
msg = "\(self.socketId!):\(channel.name):\(channelData)"
552+
} else {
553+
msg = "\(self.socketId!):\(channel.name)"
554+
}
554555

555-
if let hmac = try? HMAC(key: secretBuff, variant: .sha256).authenticate(msgBuff) {
556-
let signature = Data(bytes: hmac).toHexString()
557-
let auth = "\(self.key):\(signature)".lowercased()
556+
let secretBuff: [UInt8] = Array(secret.utf8)
557+
let msgBuff: [UInt8] = Array(msg.utf8)
558558

559-
if channel.type == .private {
560-
self.handlePrivateChannelAuth(authValue: auth, channel: channel, callback: callback)
561-
} else {
562-
self.handlePresenceChannelAuth(authValue: auth, channel: channel, channelData: channelData, callback: callback)
563-
}
564-
}
559+
if let hmac = try? HMAC(key: secretBuff, variant: .sha256).authenticate(msgBuff) {
560+
let signature = Data(bytes: hmac).toHexString()
561+
let auth = "\(self.key):\(signature)".lowercased()
565562

566-
return true
563+
if channel.type == .private {
564+
self.handlePrivateChannelAuth(authValue: auth, channel: channel, callback: callback)
565+
} else {
566+
self.handlePresenceChannelAuth(authValue: auth, channel: channel, channelData: channelData, callback: callback)
567+
}
567568
}
568-
} else {
569-
print("socketId value not found. You may not be connected.")
570-
return false
569+
570+
return true
571571
}
572572
}
573573
}
@@ -614,18 +614,18 @@ open class PusherConnection: NSObject {
614614
Creates an authentication request for the given authEndpoint
615615

616616
- parameter endpoint: The authEndpoint to which the request will be made
617-
- parameter socketID: The socketId of the connection's websocket
617+
- parameter socketId: The socketId of the connection's websocket
618618
- parameter channel: The PusherChannel to authenticate subsciption for
619619

620620
- returns: URLRequest object to be used by the function making the auth request
621621
*/
622-
fileprivate func requestForAuthValue(from endpoint: String, socketID: String, channel: PusherChannel) -> URLRequest {
622+
fileprivate func requestForAuthValue(from endpoint: String, socketId: String, channelName: String) -> URLRequest {
623623
let allowedCharacterSet = CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted
624-
let encodedChannelName = channel.name.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
624+
let encodedChannelName = channelName.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? channelName
625625

626626
var request = URLRequest(url: URL(string: endpoint)!)
627627
request.httpMethod = "POST"
628-
request.httpBody = "socket_id=\(socketID)&channel_name=\(encodedChannelName!)".data(using: String.Encoding.utf8)
628+
request.httpBody = "socket_id=\(socketId)&channel_name=\(encodedChannelName)".data(using: String.Encoding.utf8)
629629

630630
return request
631631
}

Tests/AuthenticationTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,29 @@ class AuthenticationTests: XCTestCase {
5959
waitForExpectations(timeout: 0.5)
6060
}
6161

62+
func testSubscribingToAPrivateChannelShouldMakeARequestToTheAuthEndpointWithAnEncodedChannelName() {
63+
let ex = expectation(description: "the channel should be subscribed to successfully")
64+
let channelName = "private-reservations-for-venue@venue_id=399edd2d-3f4a-43k9-911c-9e4b6bdf0f16;date=2017-01-13"
65+
66+
let dummyDelegate = DummyDelegate()
67+
dummyDelegate.ex = ex
68+
dummyDelegate.testingChannelName = channelName
69+
pusher.delegate = dummyDelegate
70+
71+
if case .endpoint(authEndpoint: let authEndpoint) = pusher.connection.options.authMethod {
72+
let jsonData = "{\"auth\":\"testKey123:12345678gfder78ikjbg\"}".data(using: String.Encoding.utf8, allowLossyConversion: false)!
73+
let urlResponse = HTTPURLResponse(url: URL(string: "\(authEndpoint)?channel_name=private-reservations-for-venue%40venue_id%3D399ccd2d-3f4a-43c9-803c-9e4b6bdf0f16%3Bdate%3D2017-01-13&socket_id=45481.3166671")!, statusCode: 200, httpVersion: nil, headerFields: nil)
74+
MockSession.mockResponse = (jsonData, urlResponse: urlResponse, error: nil)
75+
pusher.connection.URLSession = MockSession.shared
76+
}
77+
78+
let chan = pusher.subscribe(channelName)
79+
XCTAssertFalse(chan.subscribed, "the channel should not be subscribed")
80+
pusher.connect()
81+
82+
waitForExpectations(timeout: 0.5)
83+
}
84+
6285
func testSubscribingToAPrivateChannelShouldCreateAuthSignatureInternally() {
6386
let options = PusherClientOptions(
6487
authMethod: .inline(secret: "secret")

Tests/Mocks.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ open class MockWebSocket: WebSocket {
114114
self.delegate?.websocketDidReceiveMessage(socket: self, text: "{\"event\":\"pusher_internal:subscription_succeeded\",\"channel\":\"private-test-channel\",\"data\":\"{}\"}")
115115
}
116116
)
117+
} else if stringContainsElements(string, elements: ["private-reservations-for-venue@venue_id=399edd2d-3f4a-43k9-911c-9e4b6bdf0f16;date=2017-01-13", "pusher:subscribe", "testKey123:12345678gfder78ikjbg"]) {
118+
let _ = stubber.stub(
119+
functionName: "writeString",
120+
args: [string],
121+
functionToCall: {
122+
self.delegate?.websocketDidReceiveMessage(socket: self, text: "{\"event\":\"pusher_internal:subscription_succeeded\",\"channel\":\"private-reservations-for-venue@venue_id=399edd2d-3f4a-43k9-911c-9e4b6bdf0f16;date=2017-01-13\",\"data\":\"{}\"}")
123+
}
124+
)
117125
} else if stringContainsElements(string, elements: ["test-channel", "pusher:unsubscribe"]) {
118126
let _ = stubber.stub(
119127
functionName: "writeString",

0 commit comments

Comments
 (0)