Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions SessionMessagingKit/Jobs/DisplayPictureDownloadJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public enum DisplayPictureDownloadJob: JobExecutor {
using: dependencies
)

case .community(let fileId, let roomToken, let server):
case .community(let fileId, let roomToken, let server, let skipAuthentication):
guard
let info: LibSession.OpenGroupCapabilityInfo = try? LibSession.OpenGroupCapabilityInfo
.fetchOne(db, id: OpenGroup.idFor(roomToken: roomToken, server: server))
Expand All @@ -58,6 +58,7 @@ public enum DisplayPictureDownloadJob: JobExecutor {
fileId: fileId,
roomToken: roomToken,
authMethod: Authentication.community(info: info),
skipAuthentication: skipAuthentication,
using: dependencies
)
}
Expand Down Expand Up @@ -206,7 +207,7 @@ public enum DisplayPictureDownloadJob: JobExecutor {
)
db.addConversationEvent(id: id, type: .updated(.displayPictureUrl(url)))

case .community(_, let roomToken, let server):
case .community(_, let roomToken, let server, _):
_ = try? OpenGroup
.filter(id: OpenGroup.idFor(roomToken: roomToken, server: server))
.updateAllAndConfig(
Expand All @@ -228,7 +229,7 @@ extension DisplayPictureDownloadJob {
public enum Target: Codable, Hashable, CustomStringConvertible {
case profile(id: String, url: String, encryptionKey: Data)
case group(id: String, url: String, encryptionKey: Data)
case community(imageId: String, roomToken: String, server: String)
case community(imageId: String, roomToken: String, server: String, skipAuthentication: Bool = false)

var isValid: Bool {
switch self {
Expand All @@ -239,7 +240,7 @@ extension DisplayPictureDownloadJob {
encryptionKey.count == DisplayPictureManager.aes256KeyByteLength
)

case .community(let imageId, _, _): return !imageId.isEmpty
case .community(let imageId, _, _, _): return !imageId.isEmpty
}
}

Expand All @@ -249,7 +250,7 @@ extension DisplayPictureDownloadJob {
switch self {
case .profile(let id, _, _): return "profile: \(id)"
case .group(let id, _, _): return "group: \(id)"
case .community(_, let roomToken, let server): return "room: \(roomToken) on server: \(server)"
case .community(_, let roomToken, let server, _): return "room: \(roomToken) on server: \(server)"
}
}
}
Expand All @@ -274,11 +275,12 @@ extension DisplayPictureDownloadJob {

self.target = {
switch target {
case .community(let imageId, let roomToken, let server):
case .community(let imageId, let roomToken, let server, let skipAuthentication):
return .community(
imageId: imageId,
roomToken: roomToken,
server: server.lowercased() // Always in lowercase on `OpenGroup`
server: server.lowercased(), // Always in lowercase on `OpenGroup`
skipAuthentication: skipAuthentication
)

default: return target
Expand Down Expand Up @@ -358,7 +360,7 @@ extension DisplayPictureDownloadJob {

return (url == latestDisplayPictureUrl)

case .community(let imageId, let roomToken, let server):
case .community(let imageId, let roomToken, let server, _):
guard
let latestImageId: String = try? OpenGroup
.select(.imageId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public enum RetrieveDefaultOpenGroupRoomsJob: JobExecutor {
.tryFlatMap { [dependencies] authMethod -> AnyPublisher<(ResponseInfoType, Network.SOGS.CapabilitiesAndRoomsResponse), Error> in
try Network.SOGS.preparedCapabilitiesAndRooms(
authMethod: authMethod,
skipAuthentication: true,
using: dependencies
).send(using: dependencies)
}
Expand Down Expand Up @@ -157,7 +158,8 @@ public enum RetrieveDefaultOpenGroupRoomsJob: JobExecutor {
target: .community(
imageId: imageId,
roomToken: room.token,
server: Network.SOGS.defaultServer
server: Network.SOGS.defaultServer,
skipAuthentication: true
),
timestamp: (dependencies[cache: .snodeAPI].currentOffsetTimestampMs() / 1000)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ class RetrieveDefaultOpenGroupRoomsJobSpec: QuickSpec {
),
forceBlinded: false
),
skipAuthentication: true,
using: dependencies
)
}
Expand All @@ -286,6 +287,8 @@ class RetrieveDefaultOpenGroupRoomsJobSpec: QuickSpec {
requestAndPathBuildTimeout: expectedRequest.requestAndPathBuildTimeout
)
})

expect(expectedRequest?.headers).to(beEmpty())
}

// MARK: -- will retry 8 times before it fails
Expand Down Expand Up @@ -440,7 +443,8 @@ class RetrieveDefaultOpenGroupRoomsJobSpec: QuickSpec {
target: .community(
imageId: "12",
roomToken: "testRoom2",
server: Network.SOGS.defaultServer
server: Network.SOGS.defaultServer,
skipAuthentication: true
),
timestamp: 1234567890
)
Expand Down Expand Up @@ -487,7 +491,8 @@ class RetrieveDefaultOpenGroupRoomsJobSpec: QuickSpec {
target: .community(
imageId: "12",
roomToken: "testRoom2",
server: Network.SOGS.defaultServer
server: Network.SOGS.defaultServer,
skipAuthentication: true
),
timestamp: 1234567890
)
Expand Down
33 changes: 21 additions & 12 deletions SessionNetworkingKit/SOGS/SOGSAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,10 @@ public extension Network.SOGS {
private static func preparedSequence(
requests: [any ErasedPreparedRequest],
authMethod: AuthenticationMethod,
skipAuthentication: Bool = false,
using dependencies: Dependencies
) throws -> Network.PreparedRequest<Network.BatchResponseMap<Endpoint>> {
return try Network.PreparedRequest(
let preparedRequest = try Network.PreparedRequest(
request: Request(
method: .post,
endpoint: Endpoint.sequence,
Expand All @@ -169,7 +170,7 @@ public extension Network.SOGS {
additionalSignatureData: AdditionalSigningData(authMethod),
using: dependencies
)
.signed(with: Network.SOGS.signRequest, using: dependencies)
return skipAuthentication ? preparedRequest : try preparedRequest.signed(with: Network.SOGS.signRequest, using: dependencies)
}

// MARK: - Capabilities
Expand All @@ -183,9 +184,10 @@ public extension Network.SOGS {
/// could return: `{"capabilities": ["sogs", "batch"], "missing": ["magic"]}`
static func preparedCapabilities(
authMethod: AuthenticationMethod,
skipAuthentication: Bool = false,
using dependencies: Dependencies
) throws -> Network.PreparedRequest<CapabilitiesResponse> {
return try Network.PreparedRequest(
let preparedRequest = try Network.PreparedRequest(
request: Request<NoBody, Endpoint>(
endpoint: .capabilities,
authMethod: authMethod
Expand All @@ -194,7 +196,7 @@ public extension Network.SOGS {
additionalSignatureData: AdditionalSigningData(authMethod),
using: dependencies
)
.signed(with: Network.SOGS.signRequest, using: dependencies)
return skipAuthentication ? preparedRequest : try preparedRequest.signed(with: Network.SOGS.signRequest, using: dependencies)
}

// MARK: - Room
Expand All @@ -204,9 +206,10 @@ public extension Network.SOGS {
/// Rooms to which the user does not have access (e.g. because they are banned, or the room has restricted access permissions) are not included
static func preparedRooms(
authMethod: AuthenticationMethod,
skipAuthentication: Bool = false,
using dependencies: Dependencies
) throws -> Network.PreparedRequest<[Room]> {
return try Network.PreparedRequest(
let preparedRequest = try Network.PreparedRequest(
request: Request<NoBody, Endpoint>(
endpoint: .rooms,
authMethod: authMethod
Expand All @@ -215,7 +218,7 @@ public extension Network.SOGS {
additionalSignatureData: AdditionalSigningData(authMethod),
using: dependencies
)
.signed(with: Network.SOGS.signRequest, using: dependencies)
return skipAuthentication ? preparedRequest : try preparedRequest.signed(with: Network.SOGS.signRequest, using: dependencies)
}

/// Returns the details of a single room
Expand Down Expand Up @@ -317,20 +320,25 @@ public extension Network.SOGS {
/// methods for the documented behaviour of each method
static func preparedCapabilitiesAndRooms(
authMethod: AuthenticationMethod,
skipAuthentication: Bool = false,
using dependencies: Dependencies
) throws -> Network.PreparedRequest<CapabilitiesAndRoomsResponse> {
return try Network.SOGS
let preparedRequest = try Network.SOGS
.preparedSequence(
requests: [
// Get the latest capabilities for the server (in case it's a new server or the
// cached ones are stale)
preparedCapabilities(authMethod: authMethod, using: dependencies),
preparedRooms(authMethod: authMethod, using: dependencies)
preparedCapabilities(authMethod: authMethod, skipAuthentication: skipAuthentication, using: dependencies),
preparedRooms(authMethod: authMethod, skipAuthentication: skipAuthentication, using: dependencies)
],
authMethod: authMethod,
skipAuthentication: skipAuthentication,
using: dependencies
)
.signed(with: Network.SOGS.signRequest, using: dependencies)

let finalRequest = skipAuthentication ? preparedRequest : try preparedRequest.signed(with: Network.SOGS.signRequest, using: dependencies)

return finalRequest
.tryMap { (info: ResponseInfoType, response: Network.BatchResponseMap<Endpoint>) -> CapabilitiesAndRoomsResponse in
let maybeCapabilities: Network.BatchSubResponse<Network.SOGS.CapabilitiesResponse>? = (response[.capabilities] as? Network.BatchSubResponse<Network.SOGS.CapabilitiesResponse>)
let maybeRooms: Network.BatchSubResponse<[Room]>? = response.data
Expand Down Expand Up @@ -835,9 +843,10 @@ public extension Network.SOGS {
fileId: String,
roomToken: String,
authMethod: AuthenticationMethod,
skipAuthentication: Bool = false,
using dependencies: Dependencies
) throws -> Network.PreparedRequest<Data> {
return try Network.PreparedRequest(
let preparedRequest = try Network.PreparedRequest(
request: Request<NoBody, Endpoint>(
endpoint: .roomFileIndividual(roomToken, fileId),
authMethod: authMethod
Expand All @@ -847,7 +856,7 @@ public extension Network.SOGS {
requestTimeout: Network.fileDownloadTimeout,
using: dependencies
)
.signed(with: Network.SOGS.signRequest, using: dependencies)
return skipAuthentication ? preparedRequest : try preparedRequest.signed(with: Network.SOGS.signRequest, using: dependencies)
}

// MARK: - Inbox/Outbox (Message Requests)
Expand Down
97 changes: 97 additions & 0 deletions SessionNetworkingKitTests/SOGS/SOGSAPISpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,44 @@ class SOGSAPISpec: QuickSpec {

expect(preparedRequest?.path).to(equal("/sequence"))
expect(preparedRequest?.method.rawValue).to(equal("POST"))

expect(preparedRequest?.headers).toNot(beEmpty())
expect(preparedRequest?.headers).to(equal([
HTTPHeader.sogsNonce: "pK6YRtQApl4NhECGizF0Cg==",
HTTPHeader.sogsTimestamp: "1234567890",
HTTPHeader.sogsSignature: "VGVzdFNvZ3NTaWduYXR1cmU=",
HTTPHeader.sogsPubKey: "1588672ccb97f40bb57238989226cf429b575ba355443f47bc76c5ab144a96c65b"
]))
}

// MARK: ---- generates the request correctly and skips adding request headers
it("generates the request correctly and skips adding request headers") {
expect {
preparedRequest = try OpenGroupAPI.preparedCapabilitiesAndRooms(
authMethod: Authentication.community(
info: LibSession.OpenGroupCapabilityInfo(
roomToken: "",
server: "testserver",
publicKey: TestConstants.publicKey,
capabilities: []
),
forceBlinded: false
),
skipAuthentication: true,
using: dependencies
)
}.toNot(throwError())

expect(preparedRequest?.batchEndpoints.count).to(equal(2))
expect(preparedRequest?.batchEndpoints[test: 0].asType(OpenGroupAPI.Endpoint.self))
.to(equal(.capabilities))
expect(preparedRequest?.batchEndpoints[test: 1].asType(OpenGroupAPI.Endpoint.self))
.to(equal(.rooms))

expect(preparedRequest?.path).to(equal("/sequence"))
expect(preparedRequest?.method.rawValue).to(equal("POST"))

expect(preparedRequest?.headers).to(beEmpty())
}

// MARK: ---- processes a valid response correctly
Expand Down Expand Up @@ -1578,6 +1616,31 @@ class SOGSAPISpec: QuickSpec {
]))
}

// MARK: ---- generates the download destination correctly when given an id and skips adding request headers
it("generates the download destination correctly when given an id and skips adding request headers") {
expect {
preparedRequest = try OpenGroupAPI.preparedDownload(
fileId: "1",
roomToken: "roomToken",
authMethod: Authentication.community(
info: LibSession.OpenGroupCapabilityInfo(
roomToken: "",
server: "testserver",
publicKey: TestConstants.publicKey,
capabilities: []
),
forceBlinded: false
),
skipAuthentication: true,
using: dependencies
)
}.toNot(throwError())

expect(preparedRequest?.path).to(equal("/room/roomToken/file/1"))
expect(preparedRequest?.method.rawValue).to(equal("GET"))
expect(preparedRequest?.headers).to(beEmpty())
}

// MARK: ---- generates the download request correctly when given a URL
it("generates the download request correctly when given a URL") {
expect {
Expand Down Expand Up @@ -2203,6 +2266,40 @@ class SOGSAPISpec: QuickSpec {
.handleEvents(receiveOutput: { result in response = result })
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)

expect(preparedRequest?.headers).toNot(beEmpty())

expect(response).toNot(beNil())
expect(error).to(beNil())
}

// MARK: ---- triggers sending correctly without headers
it("triggers sending correctly without headers") {
var response: (info: ResponseInfoType, data: [OpenGroupAPI.Room])?

expect {
preparedRequest = try OpenGroupAPI.preparedRooms(
authMethod: Authentication.community(
info: LibSession.OpenGroupCapabilityInfo(
roomToken: "",
server: "testserver",
publicKey: TestConstants.publicKey,
capabilities: []
),
forceBlinded: false
),
skipAuthentication: true,
using: dependencies
)
}.toNot(throwError())

preparedRequest?
.send(using: dependencies)
.handleEvents(receiveOutput: { result in response = result })
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)

expect(preparedRequest?.headers).to(beEmpty())

expect(response).toNot(beNil())
expect(error).to(beNil())
Expand Down